home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 / MACD 5.bin / workbench / wb / czesc_1 / cgwbpattern101 / ilbmtoppm.lha / src / ppmtoilbm.c < prev   
C/C++ Source or Header  |  1995-04-13  |  83KB  |  2,468 lines

  1. /* ppmtoilbm.c - read a portable pixmap and produce an IFF ILBM file
  2. **
  3. ** Copyright (C) 1989 by Jef Poskanzer.
  4. ** Modified by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
  5. **  20/Jun/93:
  6. **  - 24-bit support (new options -24if, -24force)
  7. **  - HAM8 support (well, anything from HAM3 to HAM(MAXPLANES))
  8. **  - now writes up to 8 (16) planes (new options -maxplanes, -fixplanes)
  9. **  - colormap file (new option -map)
  10. **  - write colormap only (new option -cmaponly)
  11. **  - only writes CAMG chunk if it is a HAM-picture
  12. **  29/Aug/93:
  13. **  - operates row-by-row whenever possible
  14. **  - faster colorscaling with lookup-table (~20% faster on HAM pictures)
  15. **  - options -ham8 and -ham6 now imply -hamforce
  16. **  27/Nov/93:
  17. **  - byterun1 compression (this is now default) with new options:
  18. **    -compress, -nocompress, -cmethod, -savemem
  19. **  - floyd-steinberg error diffusion (for std+mapfile and HAM)
  20. **  - new options: -lace and -hires --> write CAMG chunk
  21. **  - LUT for luminance calculation (used by ppm_to_ham)
  22. **  23/Oct/94:
  23. **  - rework of mapfile handling
  24. **  - added RGB8 & RGBN image types
  25. **  - added maskplane and transparent color support
  26. **  - 24-bit & direct color modified to n-bit deep ILBM
  27. **  - removed "-savemem" option
  28. **  22/Feb/95:
  29. **  - minor bugfixes
  30. **  - fixed "-camg 0" behaviour: now writes a CAMG chunk with value 0
  31. **  - "-24if" is now default
  32. **  - "-mmethod" and "-cmethod" options accept numeric args and keywords
  33. **  - direct color (DCOL) reimplemented
  34. **  - mapfile useable for HAM
  35. **  - added HAM colormap "fixed"
  36. **  29/Mar/95:
  37. **  - added HAM colormap "rgb4" and "rgb5" (compute with 4/5-bit table)
  38. **  - added IFF text chunks
  39. **
  40. **  TODO:
  41. **  - multipalette support (PCHG chunk) for std and HAM
  42. **
  43. **
  44. **           std   HAM  deep  cmap  RGB8  RGBN
  45. **  -------+-----+-----+-----+-----+-----+-----
  46. **  BMHD     yes   yes   yes   yes   yes   yes
  47. **  CMAP     yes   (1)   no    yes   no    no
  48. **  BODY     yes   yes   yes   no    yes   yes
  49. **  CAMG     (2)   yes   (2)   no    yes   yes
  50. **  nPlanes  1-16  3-16  3-48  0     25    13
  51. **
  52. **  (1): grayscale colormap
  53. **  (2): only if "-lace", "-hires" or "-camg" option used
  54. **
  55. ** Permission to use, copy, modify, and distribute this software and its
  56. ** documentation for any purpose and without fee is hereby granted, provided
  57. ** that the above copyright notice appear in all copies and that both that
  58. ** copyright notice and this permission notice appear in supporting
  59. ** documentation.  This software is provided "as is" without express or
  60. ** implied warranty.
  61. */
  62.  
  63. #include "ppm.h"
  64. #include "ppmcmap.h"
  65. #include "pbm.h"
  66. #include "ilbm.h"
  67.  
  68. /* as long as the libfloyd & libcmap2 routines are not part of the "official"
  69.  * libppm we cheat by including the C-source here...
  70.  */
  71. #include "libfloyd.c"
  72. #include "libcmap2.c"
  73. /*#include "ppmfloyd.h"*/
  74. /*#include "ppmcmap2.h"*/
  75.  
  76. /*#define DEBUG*/
  77.  
  78. #define MODE_RGB8       6   /* RGB8: 8-bit RGB */
  79. #define MODE_RGBN       5   /* RGBN: 4-bit RGB */
  80. #define MODE_CMAP       4   /* ILBM: colormap only */
  81. #define MODE_DCOL       3   /* ILBM: direct color */
  82. #define MODE_DEEP       2   /* ILBM: deep (24-bit) */
  83. #define MODE_HAM        1   /* ILBM: hold-and-modify (HAM) */
  84. #define MODE_NONE       0   /* ILBM: colormapped */
  85.  
  86. #define HAMMODE_GRAY    0   /* HAM colormap: grayscale */
  87. #define HAMMODE_FIXED   1   /* HAM colormap: 7 "rays" in RGB cube */
  88. #define HAMMODE_MAPFILE 2   /* HAM colormap: loaded from mapfile */
  89. #define HAMMODE_RGB4    3   /* HAM colormap: compute, 4bit RGB */
  90. #define HAMMODE_RGB5    4   /* HAM colormap: compute, 5bit RGB */
  91.  
  92. #define ECS_MAXPLANES   5
  93. #define ECS_HAMPLANES   6
  94. #define AGA_MAXPLANES   8
  95. #define AGA_HAMPLANES   8
  96.  
  97. #define HAMMAXPLANES    10  /* maximum planes for HAM */
  98.  
  99. #define DEF_MAXPLANES   ECS_MAXPLANES
  100. #define DEF_HAMPLANES   ECS_HAMPLANES
  101. #define DEF_COMPRESSION cmpByteRun1
  102. #define DEF_DEEPPLANES  8
  103. #define DEF_DCOLPLANES  5
  104. #define DEF_IFMODE      MODE_DEEP
  105.  
  106. static int colorstobpp ARGS((int colors));
  107. static void put_big_short ARGS((short s));
  108. static void put_big_long ARGS((long l));
  109. #define put_byte(b)     (void)(putc((unsigned char)(b), stdout))
  110. static void write_bytes ARGS((unsigned char *buffer, int bytes));
  111. static void ppm_to_ham ARGS((FILE *fp, int cols, int rows, int maxval, pixel *colormap, int colors, int cmapmaxval, int hamplanes));
  112. static void ppm_to_deep ARGS((FILE *fp, int cols, int rows, int maxval, int bitspercolor));
  113. static void ppm_to_dcol ARGS((FILE *fp, int cols, int rows, int maxval, DirectColor *dcol));
  114. static void ppm_to_rgb8 ARGS((FILE *fp, int cols, int rows, int maxval));
  115. static void ppm_to_rgbn ARGS((FILE *fp, int cols, int rows, int maxval));
  116. static void ppm_to_std ARGS((FILE *fp, int cols, int rows, int maxval, pixel *colormap, int colors, int cmapmaxval, int maxcolors, int nPlanes));
  117. static void ppm_to_cmap ARGS((pixel *colormap, int colors, int maxval));
  118. static void write_bmhd ARGS((int cols, int rows, int nPlanes));
  119. static void write_cmap ARGS((pixel *colormap, int colors, int maxval));
  120. static long encode_row ARGS((FILE *outfile, rawtype *rawrow, int cols, int nPlanes));
  121. static long encode_maskrow ARGS((FILE *outfile, rawtype *rawrow, int cols));
  122. static int compress_row ARGS((int bytes));
  123. static void store_bodyrow ARGS((unsigned char *row, int len));
  124. static int runbyte1 ARGS((int bytes));
  125. static pixel * next_pixrow ARGS((FILE *fp, int row));
  126. static int * make_val_table ARGS((int oldmaxval, int newmaxval));
  127. static void * xmalloc ARGS((int bytes));
  128. #define MALLOC(n, type)     (type *)xmalloc((n) * sizeof(type))
  129. static void init_read ARGS((FILE *fp, int *colsP, int *rowsP, pixval *maxvalP, int *formatP, int readall));
  130. static void write_body_rows ARGS((void));
  131. static void write_camg ARGS((void));
  132. static int  length_of_text_chunks ARGS((void));
  133. static void write_text_chunks ARGS((void));
  134. #define PAD(n)      (odd(n) ? 1 : 0)    /* pad to a word */
  135.  
  136.  
  137. /* global data */
  138. static unsigned char *coded_rowbuf; /* buffer for uncompressed scanline */
  139. static unsigned char *compr_rowbuf; /* buffer for compressed scanline */
  140. static pixel **pixels;  /* PPM image (NULL for row-by-row operation) */
  141. static pixel *pixrow;   /* current row in PPM image (pointer into pixels array, or buffer for row-by-row operation) */
  142.  
  143. static long viewportmodes = 0;
  144. static int slicesize = 1;       /* rows per slice for multipalette images - NOT USED */
  145.  
  146. static unsigned char compmethod = DEF_COMPRESSION;      /* default compression */
  147. static unsigned char maskmethod = mskNone;
  148.  
  149. static pixel *transpColor = NULL;   /* transparent color */
  150. static short  transpIndex = -1;     /* index of transparent color */
  151.  
  152. static short hammapmode = HAMMODE_GRAY;
  153. static short sortcmap = 0;     /* sort colormap */
  154.  
  155. static FILE *maskfile = NULL;
  156. static bit *maskrow = NULL;
  157. static int maskcols, maskformat;
  158. #define TOTALPLANES(nplanes)       ((nplanes) + ((maskmethod == mskHasMask) ? 1 : 0))
  159.  
  160.  
  161. #define ROWS_PER_BLOCK  1024
  162. typedef struct bodyblock {
  163.     int used;
  164.     unsigned char *row[ROWS_PER_BLOCK];
  165.     int            len[ROWS_PER_BLOCK];
  166.     struct bodyblock *next;
  167. } bodyblock;
  168. static bodyblock firstblock = { 0 };
  169. static bodyblock *cur_block = &firstblock;
  170.  
  171. static char *anno_chunk, *auth_chunk, *name_chunk, *text_chunk, *copyr_chunk;
  172.  
  173. /* flags */
  174. static short compr_force = 0;   /* force compressed output, even if the image got larger  - NOT USED */
  175. static short floyd = 0;         /* apply floyd-steinberg error diffusion */
  176. static short gen_camg = 0;      /* write CAMG chunk */
  177.  
  178. #define WORSTCOMPR(bytes)       ((bytes) + (bytes)/128 + 1)
  179. #define DO_COMPRESS             (compmethod != cmpNone)
  180.  
  181.  
  182.  
  183. /* Lookup tables for fast RGB -> luminance calculation. */
  184. /* taken from ppmtopgm.c   -IUW */
  185.  
  186. static int times77[256] = {
  187.             0,    77,   154,   231,   308,   385,   462,   539,
  188.           616,   693,   770,   847,   924,  1001,  1078,  1155,
  189.          1232,  1309,  1386,  1463,  1540,  1617,  1694,  1771,
  190.          1848,  1925,  2002,  2079,  2156,  2233,  2310,  2387,
  191.          2464,  2541,  2618,  2695,  2772,  2849,  2926,  3003,
  192.          3080,  3157,  3234,  3311,  3388,  3465,  3542,  3619,
  193.          3696,  3773,  3850,  3927,  4004,  4081,  4158,  4235,
  194.          4312,  4389,  4466,  4543,  4620,  4697,  4774,  4851,
  195.          4928,  5005,  5082,  5159,  5236,  5313,  5390,  5467,
  196.          5544,  5621,  5698,  5775,  5852,  5929,  6006,  6083,
  197.          6160,  6237,  6314,  6391,  6468,  6545,  6622,  6699,
  198.          6776,  6853,  6930,  7007,  7084,  7161,  7238,  7315,
  199.          7392,  7469,  7546,  7623,  7700,  7777,  7854,  7931,
  200.          8008,  8085,  8162,  8239,  8316,  8393,  8470,  8547,
  201.          8624,  8701,  8778,  8855,  8932,  9009,  9086,  9163,
  202.          9240,  9317,  9394,  9471,  9548,  9625,  9702,  9779,
  203.          9856,  9933, 10010, 10087, 10164, 10241, 10318, 10395,
  204.         10472, 10549, 10626, 10703, 10780, 10857, 10934, 11011,
  205.         11088, 11165, 11242, 11319, 11396, 11473, 11550, 11627,
  206.         11704, 11781, 11858, 11935, 12012, 12089, 12166, 12243,
  207.         12320, 12397, 12474, 12551, 12628, 12705, 12782, 12859,
  208.         12936, 13013, 13090, 13167, 13244, 13321, 13398, 13475,
  209.         13552, 13629, 13706, 13783, 13860, 13937, 14014, 14091,
  210.         14168, 14245, 14322, 14399, 14476, 14553, 14630, 14707,
  211.         14784, 14861, 14938, 15015, 15092, 15169, 15246, 15323,
  212.         15400, 15477, 15554, 15631, 15708, 15785, 15862, 15939,
  213.         16016, 16093, 16170, 16247, 16324, 16401, 16478, 16555,
  214.         16632, 16709, 16786, 16863, 16940, 17017, 17094, 17171,
  215.         17248, 17325, 17402, 17479, 17556, 17633, 17710, 17787,
  216.         17864, 17941, 18018, 18095, 18172, 18249, 18326, 18403,
  217.         18480, 18557, 18634, 18711, 18788, 18865, 18942, 19019,
  218.         19096, 19173, 19250, 19327, 19404, 19481, 19558, 19635 };
  219. static int times150[256] = {
  220.             0,   150,   300,   450,   600,   750,   900,  1050,
  221.          1200,  1350,  1500,  1650,  1800,  1950,  2100,  2250,
  222.          2400,  2550,  2700,  2850,  3000,  3150,  3300,  3450,
  223.          3600,  3750,  3900,  4050,  4200,  4350,  4500,  4650,
  224.          4800,  4950,  5100,  5250,  5400,  5550,  5700,  5850,
  225.          6000,  6150,  6300,  6450,  6600,  6750,  6900,  7050,
  226.          7200,  7350,  7500,  7650,  7800,  7950,  8100,  8250,
  227.          8400,  8550,  8700,  8850,  9000,  9150,  9300,  9450,
  228.          9600,  9750,  9900, 10050, 10200, 10350, 10500, 10650,
  229.         10800, 10950, 11100, 11250, 11400, 11550, 11700, 11850,
  230.         12000, 12150, 12300, 12450, 12600, 12750, 12900, 13050,
  231.         13200, 13350, 13500, 13650, 13800, 13950, 14100, 14250,
  232.         14400, 14550, 14700, 14850, 15000, 15150, 15300, 15450,
  233.         15600, 15750, 15900, 16050, 16200, 16350, 16500, 16650,
  234.         16800, 16950, 17100, 17250, 17400, 17550, 17700, 17850,
  235.         18000, 18150, 18300, 18450, 18600, 18750, 18900, 19050,
  236.         19200, 19350, 19500, 19650, 19800, 19950, 20100, 20250,
  237.         20400, 20550, 20700, 20850, 21000, 21150, 21300, 21450,
  238.         21600, 21750, 21900, 22050, 22200, 22350, 22500, 22650,
  239.         22800, 22950, 23100, 23250, 23400, 23550, 23700, 23850,
  240.         24000, 24150, 24300, 24450, 24600, 24750, 24900, 25050,
  241.         25200, 25350, 25500, 25650, 25800, 25950, 26100, 26250,
  242.         26400, 26550, 26700, 26850, 27000, 27150, 27300, 27450,
  243.         27600, 27750, 27900, 28050, 28200, 28350, 28500, 28650,
  244.         28800, 28950, 29100, 29250, 29400, 29550, 29700, 29850,
  245.         30000, 30150, 30300, 30450, 30600, 30750, 30900, 31050,
  246.         31200, 31350, 31500, 31650, 31800, 31950, 32100, 32250,
  247.         32400, 32550, 32700, 32850, 33000, 33150, 33300, 33450,
  248.         33600, 33750, 33900, 34050, 34200, 34350, 34500, 34650,
  249.         34800, 34950, 35100, 35250, 35400, 35550, 35700, 35850,
  250.         36000, 36150, 36300, 36450, 36600, 36750, 36900, 37050,
  251.         37200, 37350, 37500, 37650, 37800, 37950, 38100, 38250 };
  252. static int times29[256] = {
  253.             0,    29,    58,    87,   116,   145,   174,   203,
  254.           232,   261,   290,   319,   348,   377,   406,   435,
  255.           464,   493,   522,   551,   580,   609,   638,   667,
  256.           696,   725,   754,   783,   812,   841,   870,   899,
  257.           928,   957,   986,  1015,  1044,  1073,  1102,  1131,
  258.          1160,  1189,  1218,  1247,  1276,  1305,  1334,  1363,
  259.          1392,  1421,  1450,  1479,  1508,  1537,  1566,  1595,
  260.          1624,  1653,  1682,  1711,  1740,  1769,  1798,  1827,
  261.          1856,  1885,  1914,  1943,  1972,  2001,  2030,  2059,
  262.          2088,  2117,  2146,  2175,  2204,  2233,  2262,  2291,
  263.          2320,  2349,  2378,  2407,  2436,  2465,  2494,  2523,
  264.          2552,  2581,  2610,  2639,  2668,  2697,  2726,  2755,
  265.          2784,  2813,  2842,  2871,  2900,  2929,  2958,  2987,
  266.          3016,  3045,  3074,  3103,  3132,  3161,  3190,  3219,
  267.          3248,  3277,  3306,  3335,  3364,  3393,  3422,  3451,
  268.          3480,  3509,  3538,  3567,  3596,  3625,  3654,  3683,
  269.          3712,  3741,  3770,  3799,  3828,  3857,  3886,  3915,
  270.          3944,  3973,  4002,  4031,  4060,  4089,  4118,  4147,
  271.          4176,  4205,  4234,  4263,  4292,  4321,  4350,  4379,
  272.          4408,  4437,  4466,  4495,  4524,  4553,  4582,  4611,
  273.          4640,  4669,  4698,  4727,  4756,  4785,  4814,  4843,
  274.          4872,  4901,  4930,  4959,  4988,  5017,  5046,  5075,
  275.          5104,  5133,  5162,  5191,  5220,  5249,  5278,  5307,
  276.          5336,  5365,  5394,  5423,  5452,  5481,  5510,  5539,
  277.          5568,  5597,  5626,  5655,  5684,  5713,  5742,  5771,
  278.          5800,  5829,  5858,  5887,  5916,  5945,  5974,  6003,
  279.          6032,  6061,  6090,  6119,  6148,  6177,  6206,  6235,
  280.          6264,  6293,  6322,  6351,  6380,  6409,  6438,  6467,
  281.          6496,  6525,  6554,  6583,  6612,  6641,  6670,  6699,
  282.          6728,  6757,  6786,  6815,  6844,  6873,  6902,  6931,
  283.          6960,  6989,  7018,  7047,  7076,  7105,  7134,  7163,
  284.          7192,  7221,  7250,  7279,  7308,  7337,  7366,  7395 };
  285.  
  286.  
  287. /************ parse options and figure out what kind of ILBM to write ************/
  288.  
  289.  
  290. static int get_int_val ARGS((char *string, char *option, int bot, int top));
  291. static int get_compr_method ARGS((char *string));
  292. static int get_mask_type ARGS((char *string));
  293. static int get_hammap_mode ARGS((char *string));
  294. #define NEWDEPTH(pix, table)    PPM_ASSIGN((pix), (table)[PPM_GETR(pix)], (table)[PPM_GETG(pix)], (table)[PPM_GETB(pix)])
  295.  
  296.  
  297. int
  298. main(argc, argv)
  299.     int argc;
  300.     char *argv[];
  301. {
  302.     FILE *ifp;
  303.     int argn, rows, cols, format, nPlanes;
  304.     int ifmode, forcemode, maxplanes, fixplanes, mode;
  305.     int hamplanes;
  306.     int deepbits;   /* bits per color component in deep ILBM */
  307.     DirectColor dcol;
  308. #define MAXCOLORS       (1<<maxplanes)
  309.     pixval maxval;
  310.     pixel *colormap = NULL;
  311.     int colors = 0;
  312.     pixval cmapmaxval;      /* maxval of colors in cmap */
  313.     char *mapfile, *transpname;
  314.     char *usage =
  315. "[-ilbm|-rgb8|-rgbn]\
  316.  [-ecs|-aga] [-ham6|-ham8] [-maxplanes|-mp <n>] [-fixplanes|-fp <n>]\
  317.  [-normal|-hamif|-hamforce|-24if|-24force|-deepif|-deepforce|-dcif|-dcforce|-cmaponly]\
  318.  [-hamplanes|-hambits <n>] [-hammap gray|fixed|rgb4|rgb5]\
  319.  [-deepplanes|-deepbits <n>] [-dcplanes|-dcbits <r> <g> <b>]\
  320.  [-annotation <str>] [-author <str>] [-copyright <str>] [-name <str>] [-text <str>]\
  321.  [-hires] [-lace] [-camg <hexval>]\
  322.  [-nocompress] [-cmethod 0|1|none|byterun1]\
  323.  [-mapfile <ppmfile>] [-sortcmap] [-floyd|-fs]\
  324.  [-mmethod 0|1|2|3|none|maskplane|transparentcolor|lasso]\
  325.  [-maskfile <pbmfile>] [-transparent <color>]\
  326.  [ppmfile]";
  327.  
  328.     ppm_init(&argc, argv);
  329.  
  330.     ifmode = DEF_IFMODE; forcemode = MODE_NONE;
  331.     maxplanes = DEF_MAXPLANES; fixplanes = 0;
  332.     hamplanes = DEF_HAMPLANES;
  333.     deepbits = DEF_DEEPPLANES;
  334.     dcol.r = dcol.g = dcol.b = DEF_DCOLPLANES;
  335.     mapfile = transpname = NULL;
  336.  
  337.     argn = 1;
  338.     while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) {
  339.         if( pm_keymatch(argv[argn], "-ilbm", 5) ) {
  340.             if( forcemode == MODE_RGB8 || forcemode == MODE_RGBN )
  341.                 forcemode = MODE_NONE;
  342.         }
  343.         else
  344.         if( pm_keymatch(argv[argn], "-rgb8", 5) )
  345.             forcemode = MODE_RGB8;
  346.         else
  347.         if( pm_keymatch(argv[argn], "-rgbn", 5) )
  348.             forcemode = MODE_RGBN;
  349.         else
  350.         if( pm_keymatch(argv[argn], "-maxplanes", 4) || pm_keymatch(argv[argn], "-mp", 3) ) {
  351.             if( ++argn >= argc )
  352.                 pm_usage(usage);
  353.             maxplanes = get_int_val(argv[argn], argv[argn-1], 1, MAXPLANES);
  354.             fixplanes = 0;
  355.         }
  356.         else
  357.         if( pm_keymatch(argv[argn], "-fixplanes", 4) || pm_keymatch(argv[argn], "-fp", 3) ) {
  358.             if( ++argn >= argc )
  359.                 pm_usage(usage);
  360.             fixplanes = get_int_val(argv[argn], argv[argn-1], 1, MAXPLANES);
  361.             maxplanes = fixplanes;
  362.         }
  363.         else
  364.         if( pm_keymatch(argv[argn], "-mapfile", 4) ) {
  365.             if( ++argn >= argc )
  366.                 pm_usage(usage);
  367.             mapfile = argv[argn];
  368.         }
  369.         else
  370.         if( pm_keymatch(argv[argn], "-mmethod", 3) ) {
  371.             if( ++argn >= argc )
  372.                 pm_usage(usage);
  373.             maskmethod = get_mask_type(argv[argn]);
  374.             switch( maskmethod ) {
  375.                 case mskNone:
  376.                 case mskHasMask:
  377.                 case mskHasTransparentColor:
  378.                     break;
  379.                 default:
  380.                     pm_error("masking method \"%s\" not supported yet", mskNAME[maskmethod]);
  381.             }
  382.         }
  383.         else
  384.         if( pm_keymatch(argv[argn], "-maskfile", 4) ) {
  385.             if( ++argn >= argc )
  386.                 pm_usage(usage);
  387.             maskfile = pm_openr(argv[argn]);
  388.             if( maskmethod == mskNone )
  389.                 maskmethod = mskHasMask;
  390.         }
  391.         else
  392.         if( pm_keymatch(argv[argn], "-transparent", 3) ) {
  393.             if( ++argn >= argc )
  394.                 pm_usage(usage);
  395.             transpname = argv[argn];
  396.             if( maskmethod == mskNone )
  397.                 maskmethod = mskHasTransparentColor;
  398.         }
  399.         else
  400.         if( pm_keymatch(argv[argn], "-sortcmap", 5) )
  401.             sortcmap = 1;
  402.         else
  403.         if( pm_keymatch(argv[argn], "-cmaponly", 3) ) {
  404.             forcemode = MODE_CMAP;
  405.         }
  406.         else
  407.         if( pm_keymatch(argv[argn], "-lace", 2) ) {
  408.             slicesize = 2;
  409.             viewportmodes |= vmLACE;
  410.             gen_camg = 1;
  411.         }
  412.         else
  413.         if( pm_keymatch(argv[argn], "-nolace", 4) ) {
  414.             slicesize = 1;
  415.             viewportmodes &= ~vmLACE;
  416.         }
  417.         else
  418.         if( pm_keymatch(argv[argn], "-hires", 3) ) {
  419.             viewportmodes |= vmHIRES;
  420.             gen_camg = 1;
  421.         }
  422.         else
  423.         if( pm_keymatch(argv[argn], "-nohires", 5) )
  424.             viewportmodes &= ~vmHIRES;
  425.         else
  426.         if( pm_keymatch(argv[argn], "-camg", 5) ) {
  427.             char *tail;
  428.             long value = 0L;
  429.  
  430.             if( ++argn >= argc )
  431.                 pm_usage(usage);
  432.             value = strtol(argv[argn], &tail, 16);
  433.             /* TODO: should do some error checking here */
  434.             viewportmodes |= value;
  435.             gen_camg = 1;
  436.         }
  437.         else
  438.         if( pm_keymatch(argv[argn], "-ecs", 2) ) {
  439.             maxplanes = ECS_MAXPLANES;
  440.             hamplanes = ECS_HAMPLANES;
  441.         }
  442.         else
  443.         if( pm_keymatch(argv[argn], "-aga", 3) ) {
  444.             maxplanes = AGA_MAXPLANES;
  445.             hamplanes = AGA_HAMPLANES;
  446.         }
  447.         else
  448.         if( pm_keymatch(argv[argn], "-hamplanes", 5) ) {
  449.             if( ++argn >= argc )
  450.                 pm_usage(usage);
  451.             hamplanes = get_int_val(argv[argn], argv[argn-1], 3, HAMMAXPLANES);
  452.         }
  453.         else
  454.         if( pm_keymatch(argv[argn], "-hambits", 5) ) {
  455.             if( ++argn >= argc )
  456.                 pm_usage(usage);
  457.             hamplanes = get_int_val(argv[argn], argv[argn-1], 3, HAMMAXPLANES-2) +2;
  458.         }
  459.         else
  460.         if( pm_keymatch(argv[argn], "-ham6", 5) ) {
  461.             hamplanes = ECS_HAMPLANES;
  462.             forcemode = MODE_HAM;
  463.         }
  464.         else
  465.         if( pm_keymatch(argv[argn], "-ham8", 5) ) {
  466.             hamplanes = AGA_HAMPLANES;
  467.             forcemode = MODE_HAM;
  468.         }
  469.         else
  470.         if( pm_keymatch(argv[argn], "-hammap", 5) ) {
  471.             if( ++argn >= argc )
  472.                 pm_usage(usage);
  473.             hammapmode = get_hammap_mode(argv[argn]);
  474.         }
  475.         else
  476.         if( pm_keymatch(argv[argn], "-hamif", 5) )
  477.             ifmode = MODE_HAM;
  478.         else
  479.         if( pm_keymatch(argv[argn], "-nohamif", 7) ) {
  480.             if( ifmode == MODE_HAM )
  481.                 ifmode = MODE_NONE;
  482.         }
  483.         else
  484.         if( pm_keymatch(argv[argn], "-hamforce", 4) )
  485.             forcemode = MODE_HAM;
  486.         else
  487.         if( pm_keymatch(argv[argn], "-nohamforce", 6) ) {
  488.             if( forcemode == MODE_HAM )
  489.                 forcemode = MODE_NONE;
  490.         }
  491.         else
  492.         if( pm_keymatch(argv[argn], "-24if", 4) ) {
  493.             ifmode = MODE_DEEP;
  494.             deepbits = 8;
  495.         }
  496.         else
  497.         if( pm_keymatch(argv[argn], "-no24if", 6) ) {
  498.             if( ifmode == MODE_DEEP )
  499.                 ifmode = MODE_NONE;
  500.         }
  501.         else
  502.         if( pm_keymatch(argv[argn], "-24force", 3) ) {
  503.             forcemode = MODE_DEEP;
  504.             deepbits = 8;
  505.         }
  506.         else
  507.         if( pm_keymatch(argv[argn], "-no24force", 5) ) {
  508.             if( forcemode == MODE_DEEP )
  509.                 forcemode = MODE_NONE;
  510.         }
  511.         else
  512.         if( pm_keymatch(argv[argn], "-deepplanes", 6) ) {
  513.             if( ++argn >= argc )
  514.                 pm_usage(usage);
  515.             deepbits = get_int_val(argv[argn], argv[argn-1], 3, 3*MAXPLANES);
  516.             if( deepbits % 3 != 0 )
  517.                 pm_error("option \"%s\" argument value must be divisible by 3", argv[argn-1]);
  518.             deepbits /= 3;
  519.         }
  520.         else
  521.         if( pm_keymatch(argv[argn], "-deepbits", 6) ) {
  522.             if( ++argn >= argc )
  523.                 pm_usage(usage);
  524.             deepbits = get_int_val(argv[argn], argv[argn-1], 1, MAXPLANES);
  525.         }
  526.         else
  527.         if( pm_keymatch(argv[argn], "-deepif", 6) )
  528.             ifmode = MODE_DEEP;
  529.         else
  530.         if( pm_keymatch(argv[argn], "-nodeepif", 8) ) {
  531.             if( ifmode == MODE_DEEP )
  532.                 ifmode = MODE_NONE;
  533.         }
  534.         else
  535.         if( pm_keymatch(argv[argn], "-deepforce", 5) )
  536.             forcemode = MODE_DEEP;
  537.         else
  538.         if( pm_keymatch(argv[argn], "-nodeepforce", 7) ) {
  539.             if( forcemode == MODE_DEEP )
  540.                 forcemode = MODE_NONE;
  541.         }
  542.         else
  543.         if( pm_keymatch(argv[argn], "-dcif", 4) )
  544.             ifmode = MODE_DCOL;
  545.         else
  546.         if( pm_keymatch(argv[argn], "-nodcif", 6) ) {
  547.             if( ifmode == MODE_DCOL )
  548.                 ifmode = MODE_NONE;
  549.         }
  550.         else
  551.         if( pm_keymatch(argv[argn], "-dcforce", 4) )
  552.             forcemode = MODE_DCOL;
  553.         else
  554.         if( pm_keymatch(argv[argn], "-nodcforce", 6) ) {
  555.             if( forcemode == MODE_DCOL )
  556.                 forcemode = MODE_NONE;
  557.         }
  558.         else
  559.         if( pm_keymatch(argv[argn], "-dcbits", 4) || pm_keymatch(argv[argn], "-dcplanes", 4) ) {
  560.             if( argc - argn < 4 )
  561.                 pm_usage(usage);
  562.             dcol.r = get_int_val(argv[argn+1], argv[argn], 1, MAXPLANES);
  563.             dcol.g = get_int_val(argv[argn+2], argv[argn], 1, MAXPLANES);
  564.             dcol.b = get_int_val(argv[argn+3], argv[argn], 1, MAXPLANES);
  565.             argn += 3;
  566.         }
  567.         else
  568.         if( pm_keymatch(argv[argn], "-normal", 4) ) {
  569.             ifmode = forcemode = MODE_NONE;
  570.             compmethod = DEF_COMPRESSION;
  571.         }
  572.         else
  573.         if( pm_keymatch(argv[argn], "-compress", 4) ) {
  574.             compr_force = 1;
  575.             if( compmethod == cmpNone )
  576. #if DEF_COMPRESSION == cmpNone
  577.                     compmethod = cmpByteRun1;
  578. #else
  579.                     compmethod = DEF_COMPRESSION;
  580. #endif
  581.         }
  582.         else
  583.         if( pm_keymatch(argv[argn], "-nocompress", 4) ) {
  584.             compr_force = 0;
  585.             compmethod = cmpNone;
  586.         }
  587.         else
  588.         if( pm_keymatch(argv[argn], "-cmethod", 4) ) {
  589.             if( ++argn >= argc )
  590.                 pm_usage(usage);
  591.             compmethod = get_compr_method(argv[argn]);
  592.         }
  593.         else
  594.         if( pm_keymatch(argv[argn], "-floyd", 3) || pm_keymatch(argv[argn], "-fs", 3) )
  595.             floyd = 1;
  596.         else
  597.         if( pm_keymatch(argv[argn], "-nofloyd", 5) || pm_keymatch(argv[argn], "-nofs", 5) )
  598.             floyd = 0;
  599.         else
  600.         if( pm_keymatch(argv[argn], "-annotation", 3) ) {
  601.             if( ++argn >= argc )
  602.                 pm_usage(usage);
  603.             anno_chunk = argv[argn];
  604.         }
  605.         else
  606.         if( pm_keymatch(argv[argn], "-author", 3) ) {
  607.             if( ++argn >= argc )
  608.                 pm_usage(usage);
  609.             auth_chunk = argv[argn];
  610.         }
  611.         else
  612.         if( pm_keymatch(argv[argn], "-copyright", 4) ) {
  613.             if( ++argn >= argc )
  614.                 pm_usage(usage);
  615.             copyr_chunk = argv[argn];
  616.         }
  617.         else
  618.         if( pm_keymatch(argv[argn], "-name", 3) ) {
  619.             if( ++argn >= argc )
  620.                 pm_usage(usage);
  621.             name_chunk = argv[argn];
  622.         }
  623.         else
  624.         if( pm_keymatch(argv[argn], "-text", 3) ) {
  625.             if( ++argn >= argc )
  626.                 pm_usage(usage);
  627.             text_chunk = argv[argn];
  628.         }
  629.         else
  630.             pm_usage(usage);
  631.         ++argn;
  632.     }
  633.  
  634.     if( argn < argc ) {
  635.         ifp = pm_openr(argv[argn]);
  636.         ++argn;
  637.     }
  638.     else
  639.         ifp = stdin;
  640.  
  641.     if( argn != argc )
  642.         pm_usage( usage );
  643.  
  644. #if 0
  645.     if( forcemode != MODE_NONE && mapfile != NULL )
  646.         pm_message("warning - mapfile only used for normal ILBMs");
  647. #endif
  648.  
  649.     mode = forcemode;
  650.     switch( forcemode ) {
  651.         case MODE_HAM:
  652.             if( hammapmode == HAMMODE_RGB4 || hammapmode == HAMMODE_RGB5 )
  653.                 init_read(ifp, &cols, &rows, &maxval, &format, 1);
  654.             else
  655.                 init_read(ifp, &cols, &rows, &maxval, &format, 0);
  656.             /*pm_message("hamforce option used - proceeding to write a HAM%d file", hamplanes);*/
  657.             break;
  658.         case MODE_DCOL:
  659.         case MODE_DEEP:
  660.             mapfile = NULL;
  661.             init_read(ifp, &cols, &rows, &maxval, &format, 0);
  662.             /*pm_message("24force/deepforce option used - proceeding to write a %d-bit \'deep\' ILBM", deepbits*3);*/
  663.             break;
  664.         case MODE_RGB8:
  665.             mapfile = NULL;
  666.             init_read(ifp, &cols, &rows, &maxval, &format, 0);
  667.             /*pm_message("rgb8 option used - proceeding to write an IFF-RGB8 (24-bit RGB) file");*/
  668.             break;
  669.         case MODE_RGBN:
  670.             mapfile = NULL;
  671.             init_read(ifp, &cols, &rows, &maxval, &format, 0);
  672.             /*pm_message("rgbn option used - proceeding to write an IFF-RGBN (12-bit RGB) file");*/
  673.             break;
  674.         case MODE_CMAP:
  675.             /* Figure out the colormap. */
  676.             pm_message("computing colormap...");
  677.             colormap = ppm_mapfiletocolorrow(ifp, MAXCOLORS, &colors, &cmapmaxval);
  678.             if( colormap == NULL )
  679.                 pm_error("too many colors - try doing a 'ppmquant %d'", MAXCOLORS);
  680.             pm_message("%d colors found", colors);
  681.             break;
  682.         default:
  683.             if( mapfile )
  684.                 init_read(ifp, &cols, &rows, &maxval, &format, 0);
  685.             else {
  686.                 init_read(ifp, &cols, &rows, &maxval, &format, 1);  /* read file into memory */
  687.                 pm_message("computing colormap...");
  688.                 colormap = ppm_computecolorrow(pixels, cols, rows, MAXCOLORS, &colors);
  689.                 if( colormap ) {
  690.                     cmapmaxval = maxval;
  691.                     pm_message("%d colors found", colors);
  692.                     nPlanes = colorstobpp(colors);
  693.                     if( fixplanes > nPlanes )
  694.                         nPlanes = fixplanes;
  695.                 }
  696.                 else {  /* too many colors */
  697.                     mode = ifmode;
  698.                     switch( ifmode ) {
  699.                         case MODE_HAM:
  700.                             pm_message("too many colors for %d planes - proceeding to write a HAM%d file", maxplanes, hamplanes);
  701.                             pm_message("if you want a non-HAM file, try doing a 'ppmquant %d'", MAXCOLORS);
  702.                             break;
  703.                         case MODE_DCOL:
  704.                             pm_message("too many colors for %d planes - proceeding to write a %d:%d:%d direct color ILBM", maxplanes, dcol.r, dcol.g, dcol.b);
  705.                             pm_message("if you want a non-direct color file, try doing a 'ppmquant %d'", MAXCOLORS);
  706.                             break;
  707.                         case MODE_DEEP:
  708.                             pm_message("too many colors for %d planes - proceeding to write a %d-bit \'deep\' ILBM", maxplanes, deepbits*3);
  709.                             pm_message("if you want a non-deep file, try doing a 'ppmquant %d'", MAXCOLORS);
  710.                             break;
  711.                         default:
  712.                             pm_error("too many colors for %d planes - try doing a 'ppmquant %d'", maxplanes, MAXCOLORS);
  713.                             break;
  714.                     }
  715.                 }
  716.             }
  717.     }
  718.  
  719.     if( mapfile ) {
  720.         FILE *mapfp;
  721.  
  722.         pm_message("reading colormap file...");
  723.         mapfp = pm_openr(mapfile);
  724.         colormap = ppm_mapfiletocolorrow(mapfp, MAXCOLORS, &colors, &cmapmaxval);
  725.         pm_close(mapfp);
  726.         if( colormap == NULL )
  727.             pm_error("too many colors in mapfile for %d planes", maxplanes);
  728.         if( colors == 0 )
  729.             pm_error("empty colormap??");
  730.         pm_message("%d colors found in colormap", colors);
  731.     }
  732.  
  733.  
  734. #if 0
  735.             /* if the maxvals of the ppmfile and the mapfile are the same,
  736.              * then the scaling to MAXCOLVAL (if necessary) will be done by
  737.                  * the write_cmap() function.
  738.                  * Otherwise scale them both to MAXCOLVAL.
  739.                  */
  740.                 if( maxval != mapmaxval ) {
  741.                     if( mapmaxval != MAXCOLVAL ) {
  742.                         int *table;
  743.                         int col;
  744.                         pm_message("colormap maxval is not %d - rescaling colormap...", MAXCOLVAL);
  745.                         table = make_val_table(mapmaxval, MAXCOLVAL);
  746.                         for( col = 0; col < colors; ++col )
  747.                                 NEWDEPTH(colormap[col], table);
  748.                         mapmaxval = MAXCOLVAL;
  749.                         free(table);
  750.                     }
  751.  
  752.                     if( maxval != mapmaxval ) {
  753.                         int col, row;
  754.                         int *table;
  755.                         pixel *pP;
  756.  
  757.                         pm_message("rescaling colors of picture...");
  758.                         table = make_val_table(maxval, mapmaxval);
  759.                         for( row = 0; row < rows; ++row )
  760.                             for( col = 0, pP = pixels[row]; col < cols; ++col, ++pP )
  761.                                 NEWDEPTH(*pP, table);   /* was PPM_DEPTH( *pP, *pP, maxval, mapmaxval ); */
  762.                         maxval = mapmaxval;
  763.                         free(table);
  764.                     }
  765.                 }
  766. #endif
  767.  
  768.     if( maskmethod != mskNone ) {
  769.         if( transpname ) {
  770.             transpColor = MALLOC(1, pixel);
  771.             *transpColor = ppm_parsecolor(transpname, maxval);
  772.         }
  773.         if( maskfile ) {
  774.             int maskrows;
  775.             pbm_readpbminit(maskfile, &maskcols, &maskrows, &maskformat);
  776.             if( maskcols < cols || maskrows < rows )
  777.                 pm_error("maskfile too small - try scaling it");
  778.             if( maskcols > cols || maskrows > rows )
  779.                 pm_message("warning - maskfile larger than image");
  780.         }
  781.         else
  782.             maskcols = rows;
  783.         maskrow = pbm_allocrow(maskcols);
  784.     }
  785.  
  786.     if( mode != MODE_CMAP ) {
  787.         register int i;
  788.         coded_rowbuf = MALLOC(RowBytes(cols), unsigned char);
  789.         for( i = 0; i < RowBytes(cols); i++ )
  790.             coded_rowbuf[i] = 0;
  791.         if( DO_COMPRESS )
  792.             compr_rowbuf = MALLOC(WORSTCOMPR(RowBytes(cols)), unsigned char);
  793.     }
  794.  
  795.     switch( mode ) {
  796.         case MODE_HAM:
  797. #if 0
  798.             if( !(PPM_FORMAT_TYPE(format) == PPM_TYPE) ) {
  799.                 floyd = 0;
  800.                 hammapmode = MODE_GRAY;
  801.             }
  802. #endif
  803.             viewportmodes |= vmHAM;
  804.             ppm_to_ham(ifp, cols, rows, maxval, colormap, colors, cmapmaxval, hamplanes);
  805.             break;
  806.         case MODE_DEEP:
  807.             ppm_to_deep(ifp, cols, rows, maxval, deepbits);
  808.             break;
  809.         case MODE_DCOL:
  810.             ppm_to_dcol(ifp, cols, rows, maxval, &dcol);
  811.             break;
  812.         case MODE_RGB8:
  813.             ppm_to_rgb8(ifp, cols, rows, maxval);
  814.             break;
  815.         case MODE_RGBN:
  816.             ppm_to_rgbn(ifp, cols, rows, maxval);
  817.             break;
  818.         case MODE_CMAP:
  819.             ppm_to_cmap(colormap, colors, cmapmaxval);
  820.             break;
  821.         default:
  822.             if( mapfile == NULL )
  823.                 floyd = 0;          /* would only slow down conversion */
  824.             ppm_to_std(ifp, cols, rows, maxval, colormap, colors, cmapmaxval, MAXCOLORS, nPlanes);
  825.             break;
  826.     }
  827.     pm_close(ifp);
  828.     exit(0);
  829.     /*NOTREACHED*/
  830. }
  831.  
  832.  
  833. static int
  834. get_int_val(string, option, bot, top)
  835.     char *string, *option;
  836.     int bot, top;
  837. {
  838.     int val;
  839.  
  840.     if( sscanf(string, "%d", &val) != 1 )
  841.         pm_error("option \"%s\" needs integer argument", option);
  842.  
  843.     if( val < bot || val > top )
  844.         pm_error("option \"%s\" argument value out of range (%d..%d)", option, bot, top);
  845.  
  846.     return val;
  847. }
  848.  
  849.  
  850. static int
  851. get_compr_method(string)
  852.     char *string;
  853. {
  854.     if( pm_keymatch(string, "none", 1) || pm_keymatch(string, "0", 1) )
  855.         return cmpNone;
  856.     else
  857.     if( pm_keymatch(string, "byterun1", 1) || pm_keymatch(string, "1", 1) )
  858.         return cmpByteRun1;
  859.  
  860.     pm_error("unknown compression method: %s", string);
  861. }
  862.  
  863.  
  864. static int
  865. get_mask_type(string)
  866.     char *string;
  867. {
  868.     if( pm_keymatch(string, "none", 1) || pm_keymatch(string, "0", 1) )
  869.         return mskNone;
  870.     else
  871.     if( pm_keymatch(string, "plane", 1) || pm_keymatch(string, "maskplane", 1) ||
  872.         pm_keymatch(string, "1", 1) )
  873.         return mskHasMask;
  874.     else
  875.     if( pm_keymatch(string, "transparentcolor", 1) || pm_keymatch(string, "2", 1) )
  876.         return mskHasTransparentColor;
  877.     else
  878.     if( pm_keymatch(string, "lasso", 1) || pm_keymatch(string, "3", 1) )
  879.         return mskLasso;
  880.  
  881.     pm_error("unknown masking method: %s", string);
  882. }
  883.  
  884.  
  885. static int
  886. get_hammap_mode(string)
  887.     char *string;
  888. {
  889.     if( pm_keymatch(string, "grey", 1) || pm_keymatch(string, "gray", 1) )
  890.         return HAMMODE_GRAY;
  891.     else
  892.     if( pm_keymatch(string, "fixed", 1) )
  893.         return HAMMODE_FIXED;
  894.     else
  895.     if( pm_keymatch(string, "rgb4", 4) )
  896.         return HAMMODE_RGB4;
  897.     else
  898.     if( pm_keymatch(string, "rgb5", 4) )
  899.         return HAMMODE_RGB5;
  900.  
  901.     pm_error("unknown HAM colormap selection mode: %s", string);
  902. }
  903.  
  904.  
  905. /************ colormap file ************/
  906.  
  907. static void
  908. ppm_to_cmap(colorrow, colors, maxval)
  909.     pixel *colorrow;
  910.     int colors;
  911.     int maxval;
  912. {
  913.     int formsize, cmapsize;
  914.  
  915.     cmapsize = colors * 3;
  916.  
  917.     formsize =
  918.         4 +                                 /* ILBM */
  919.         4 + 4 + BitMapHeaderSize +          /* BMHD size header */
  920.         4 + 4 + cmapsize + PAD(cmapsize) +  /* CMAP size colormap */
  921.         length_of_text_chunks();
  922.  
  923.     put_big_long(ID_FORM);
  924.     put_big_long(formsize);
  925.     put_big_long(ID_ILBM);
  926.  
  927.     write_bmhd(0, 0, 0);
  928.     write_text_chunks();
  929.     write_cmap(colorrow, colors, maxval);
  930. }
  931.  
  932. /************ HAM ************/
  933.  
  934. static long do_ham_body     ARGS((FILE *ifp, FILE *ofp, int cols, int rows, pixval maxval,
  935.                 pixval hammaxval, int nPlanes, pixel *cmap, int colors));
  936.  
  937.  
  938. static int hcmp ARGS((void *va, void *vb));
  939. static pixel *compute_ham_cmap ARGS((int cols, int rows, int maxval, int maxcolors, int *colorsP, int hbits));
  940.  
  941.  
  942. typedef struct {
  943.     long count;
  944.     pixval r, g, b;
  945. } hentry;
  946.  
  947.  
  948. static int
  949. hcmp(va, vb)
  950.     void *va, *vb;
  951. {
  952.     return(((hentry *)vb)->count - ((hentry *)va)->count);  /* reverse sort, highest count first */
  953. }
  954.  
  955.  
  956. static pixel *
  957. compute_ham_cmap(cols, rows, maxval, maxcolors, colorsP, hbits)
  958.     int cols, rows, maxval, maxcolors;
  959.     int *colorsP;
  960.     int hbits;
  961. {
  962.     int colors;
  963.     hentry *hmap;
  964.     pixel *cmap, *pP;
  965.     pixval hmaxval;
  966.     int i, r, g, b, col, row, *htable;
  967.     unsigned long dist, maxdist;
  968.  
  969.     pm_message("initializing HAM colormap...");
  970.  
  971.     colors = 1<<(3*hbits);
  972.     hmap = pm_allocrow(colors, sizeof(hentry));
  973.     hmaxval = pm_bitstomaxval(hbits);
  974.  
  975.     i = 0;
  976.     for( r = 0; r <= hmaxval; r++ ) {
  977.         for( g = 0; g <= hmaxval; g++ ) {
  978.             for( b = 0; b <= hmaxval; b++ ) {
  979.                 hmap[i].r = r; hmap[i].g = g; hmap[i].b = b;
  980.                 hmap[i].count = 0;
  981.                 i++;
  982.             }
  983.         }
  984.     }
  985.  
  986.     htable = make_val_table(maxval, hmaxval);
  987.     for( row = 0; row < rows; row++ ) {
  988.         for( col = 0, pP = pixels[row]; col < cols; col++, pP++ ) {
  989.             r = PPM_GETR(*pP); g = PPM_GETG(*pP); b = PPM_GETB(*pP);
  990.             i = (htable[r]<<(2*hbits)) + (htable[g]<<hbits) + htable[b];
  991.             hmap[i].count++;
  992.         }
  993.     }
  994.     free(htable);
  995.  
  996.     qsort((void *)hmap, colors, sizeof(hentry), hcmp);
  997.     for( i = colors-1; i >= 0; i-- ) {
  998.         if( hmap[i].count )
  999.             break;
  1000.     }
  1001.     colors = i+1;
  1002.  
  1003.     if( colors > maxcolors ) {
  1004.         pm_message("selecting HAM colormap from %d colors...", colors);
  1005.         for( maxdist = 1; ; maxdist++ ) {
  1006.             for( col = colors-1; col > 0; col-- ) {
  1007.                 r = hmap[col].r; g = hmap[col].g; b = hmap[col].b;
  1008. #if 0
  1009.                 for( i = col-1; i >= 0; i-- ) {
  1010. #endif
  1011.                 for( i = 0; i < col; i++ ) {
  1012.                     register int tmp;
  1013.  
  1014.                     tmp = hmap[i].r - r; dist = tmp * tmp;
  1015.                     tmp = hmap[i].g - g; dist += tmp * tmp;
  1016.                     tmp = hmap[i].b - b; dist += tmp * tmp;
  1017.  
  1018.                     if( dist <= maxdist ) {
  1019. #if 1
  1020.                         int sum = hmap[i].count + hmap[col].count;
  1021.  
  1022.                         hmap[i].r = (hmap[i].r * hmap[i].count + r * hmap[col].count + sum/2)/sum;
  1023.                         hmap[i].g = (hmap[i].g * hmap[i].count + g * hmap[col].count + sum/2)/sum;
  1024.                         hmap[i].b = (hmap[i].b * hmap[i].count + b * hmap[col].count + sum/2)/sum;
  1025.                         hmap[i].count = sum;
  1026. #else
  1027.                         hmap[i].count += hmap[col].count;
  1028. #endif
  1029.  
  1030.                         hmap[col] = hmap[i];    /* temp store */
  1031.                         for( tmp = i-1; tmp >= 0 && hmap[tmp].count < hmap[col].count; tmp-- )
  1032.                             hmap[tmp+1] = hmap[tmp];
  1033.                         hmap[tmp+1] = hmap[col];
  1034.  
  1035.                         for( tmp = col; tmp < colors-1; tmp++ )
  1036.                             hmap[tmp] = hmap[tmp+1];
  1037.                         if( --colors <= maxcolors )
  1038.                             goto out;
  1039.                         break;
  1040.                     }
  1041.                 }
  1042.             }
  1043. #ifdef DEBUG
  1044.             pm_message("\tmaxdist=%ld: %d colors left", maxdist, colors);
  1045. #endif
  1046.         }
  1047.     }
  1048. out:
  1049.     pm_message("%d colors in HAM colormap", colors);
  1050.  
  1051.     cmap = ppm_allocrow(colors);
  1052.     *colorsP = colors;
  1053.  
  1054.     for( i = 0; i < colors; i++ ) {
  1055.         r = hmap[i].r; g = hmap[i].g; b = hmap[i].b;
  1056.         PPM_ASSIGN(cmap[i], r, g, b);
  1057.     }
  1058.  
  1059.     ppm_freerow(hmap);
  1060.     return cmap;
  1061. }
  1062.  
  1063.  
  1064. static void
  1065. ppm_to_ham(fp, cols, rows, maxval, colormap, colors, cmapmaxval, hamplanes)
  1066.     FILE *fp;
  1067.     int cols, rows, maxval;
  1068.     pixel *colormap;
  1069.     int colors, cmapmaxval, hamplanes;
  1070. {
  1071.     int hamcolors, nPlanes, i, hammaxval;
  1072.     long oldsize, bodysize, formsize, cmapsize;
  1073.     int *table = NULL;
  1074.  
  1075.     if( maskmethod == mskHasTransparentColor ) {
  1076.         pm_message("masking method \"%s\" not usable with HAM - using \"%s\" instead",
  1077.                     mskNAME[mskHasTransparentColor], mskNAME[mskHasMask]);
  1078.         maskmethod = mskHasMask;
  1079.     }
  1080.  
  1081.     hamcolors = 1 << (hamplanes-2);
  1082.     hammaxval = pm_bitstomaxval(hamplanes-2);
  1083.  
  1084.     if( colors == 0 ) {
  1085.         /* no colormap, make our own */
  1086.         switch( hammapmode ) {
  1087.             case HAMMODE_GRAY:
  1088.                 colors = hamcolors;
  1089.                 colormap = MALLOC(colors, pixel);
  1090. #ifdef DEBUG
  1091.                 pm_message("generating grayscale colormap");
  1092. #endif
  1093.                 table = make_val_table(hammaxval, MAXCOLVAL);
  1094.                 for( i = 0; i < colors; i++ )
  1095.                     PPM_ASSIGN(colormap[i], table[i], table[i], table[i]);
  1096.                 free(table);
  1097.                 cmapmaxval = MAXCOLVAL;
  1098.                 break;
  1099.             case HAMMODE_FIXED: {
  1100.                 int entries, val;
  1101.                 double step;
  1102.  
  1103. #ifdef DEBUG
  1104.                 pm_message("generating rgb colormap");
  1105. #endif
  1106.                 /* generate a colormap of 7 "rays" in an RGB color cube:
  1107.                         r, g, b, r+g, r+b, g+b, r+g+b
  1108.                    we need one colormap entry for black, so the number of
  1109.                    entries per ray is (maxcolors-1)/7 */
  1110.  
  1111.                 entries = (hamcolors-1)/7;
  1112.                 colors = 7*entries+1;
  1113.                 colormap = MALLOC(colors, pixel);
  1114.                 step = (double)MAXCOLVAL / (double)entries;
  1115.  
  1116.                 PPM_ASSIGN(colormap[0], 0, 0, 0);
  1117.                 for( i = 1; i <= entries; i++ ) {
  1118.                     val = (int)((double)i * step);
  1119.                     PPM_ASSIGN(colormap[          i], val,   0,   0);   /* r */
  1120.                     PPM_ASSIGN(colormap[  entries+i],   0, val,   0);   /* g */
  1121.                     PPM_ASSIGN(colormap[2*entries+i],   0,   0, val);   /* b */
  1122.                     PPM_ASSIGN(colormap[3*entries+i], val, val,   0);   /* r+g */
  1123.                     PPM_ASSIGN(colormap[4*entries+i], val,   0, val);   /* r+b */
  1124.                     PPM_ASSIGN(colormap[5*entries+i],   0, val, val);   /* g+b */
  1125.                     PPM_ASSIGN(colormap[6*entries+i], val, val, val);   /* r+g+b */
  1126.                 }
  1127.                 cmapmaxval = MAXCOLVAL;
  1128.             }
  1129.             break;
  1130.             case HAMMODE_RGB4:
  1131.                 colormap = compute_ham_cmap(cols, rows, maxval, hamcolors, &colors, 4);
  1132.                 cmapmaxval = 15;
  1133.                 break;
  1134.             case HAMMODE_RGB5:
  1135.                 colormap = compute_ham_cmap(cols, rows, maxval, hamcolors, &colors, 5);
  1136.                 cmapmaxval = 31;
  1137.                 break;
  1138.             default:
  1139.                 pm_error("ppm_to_ham(): unknown hammapmode - can\'t happen");
  1140.         }
  1141.     }
  1142.     else {
  1143.         hammapmode = HAMMODE_MAPFILE;
  1144.         if( colors > hamcolors ) {
  1145.             pm_message("colormap too large - using first %d colors", hamcolors);
  1146.             colors = hamcolors;
  1147.         }
  1148.     }
  1149.  
  1150.     if( cmapmaxval != maxval ) {
  1151.         int i, *table;
  1152.         pixel *newcmap;
  1153.  
  1154.         newcmap = ppm_allocrow(colors);
  1155.         table = make_val_table(cmapmaxval, maxval);
  1156.         for( i = 0; i < colors; i++ )
  1157.             PPM_ASSIGN(newcmap[i], table[PPM_GETR(colormap[i])], table[PPM_GETG(colormap[i])], table[PPM_GETB(colormap[i])]);
  1158.         free(table);
  1159.         ppm_freerow(colormap);
  1160.         colormap = newcmap;
  1161.     }
  1162.     if( sortcmap )
  1163.         ppm_sortcolorrow(colormap, colors, PPM_STDSORT);
  1164.  
  1165.     nPlanes = hamplanes;
  1166.     cmapsize = colors * 3;
  1167.  
  1168.     bodysize = oldsize = rows * TOTALPLANES(nPlanes) * RowBytes(cols);
  1169.     if( DO_COMPRESS ) {
  1170.         bodysize = do_ham_body(fp, NULL, cols, rows, maxval, hammaxval, nPlanes, colormap, colors);
  1171.         /*bodysize = do_ham_body(fp, NULL, cols, rows, maxval, hammaxval, nPlanes, colbits, nocolor);*/
  1172.         if( bodysize > oldsize )
  1173.             pm_message("warning - %s compression increases BODY size by %d%%", cmpNAME[compmethod], 100*(bodysize-oldsize)/oldsize);
  1174.         else
  1175.             pm_message("BODY compression (%s): %d%%", cmpNAME[compmethod], 100*(oldsize-bodysize)/oldsize);
  1176. #if 0
  1177.         if( bodysize > oldsize && !compr_force ) {
  1178.             pm_message("%s compression would increase body size by %d%%", cmpNAME[compmethod], 100*(bodysize-oldsize)/oldsize);
  1179.             pm_message("writing uncompressed image");
  1180.             compmethod = cmpNone;
  1181.             bodysize = oldsize;
  1182.         }
  1183. #endif
  1184.     }
  1185.  
  1186.  
  1187.     formsize =
  1188.         4 +                                 /* ILBM */
  1189.         4 + 4 + BitMapHeaderSize +          /* BMHD size header */
  1190.         4 + 4 + CAMGChunkSize +             /* CAMG size viewportmodes */
  1191.         4 + 4 + cmapsize + PAD(cmapsize) +  /* CMAP size colormap */
  1192.         4 + 4 + bodysize + PAD(bodysize) +  /* BODY size data */
  1193.         length_of_text_chunks();
  1194.  
  1195.     put_big_long(ID_FORM);
  1196.     put_big_long(formsize);
  1197.     put_big_long(ID_ILBM);
  1198.  
  1199.     write_bmhd(cols, rows, nPlanes);
  1200.     write_text_chunks();
  1201.     write_camg();       /* HAM requires CAMG chunk */
  1202.     write_cmap(colormap, colors, maxval);
  1203.  
  1204.     /* write body */
  1205.     put_big_long(ID_BODY);
  1206.     put_big_long(bodysize);
  1207.     if( DO_COMPRESS )
  1208.         write_body_rows();
  1209.     else
  1210.         do_ham_body(fp, NULL, cols, rows, maxval, hammaxval, nPlanes, colormap, colors);
  1211.         /*do_ham_body(fp, stdout, cols, rows, maxval, hammaxval, nPlanes, colbits, nocolor);*/
  1212. }
  1213.  
  1214.  
  1215. static long
  1216. #ifdef __STDC__
  1217. do_ham_body(FILE *ifp, FILE *ofp, int cols, int rows,
  1218.             pixval maxval, pixval hammaxval, int nPlanes,
  1219.             pixel *colormap, int colors)
  1220. #else
  1221. do_ham_body(ifp, ofp, cols, rows, maxval, hammaxval, nPlanes, colormap, colors)
  1222.     FILE *ifp, *ofp;
  1223.     int cols, rows;
  1224.     pixval maxval;      /* maxval of image color components */
  1225.     pixval hammaxval;   /* maxval of HAM color changes */
  1226.     int nPlanes;
  1227.     pixel *colormap;
  1228.     int colors;
  1229. #endif
  1230. {
  1231.     register int col, row, i;
  1232.     pixel *pP;
  1233.     rawtype *raw_rowbuf;
  1234.     ppm_fs_info *fi = NULL;
  1235.     colorhash_table cht, cht2;
  1236.     long bodysize = 0;
  1237.     int *itoh;      /* table image -> ham */
  1238.     int usehash = 1;
  1239.     int colbits;
  1240.     int hamcode_red, hamcode_green, hamcode_blue;
  1241.  
  1242.     raw_rowbuf = MALLOC(cols, rawtype);
  1243.  
  1244.     cht = ppm_colorrowtocolorhash(colormap, colors);
  1245.     cht2 = ppm_alloccolorhash();
  1246.     colbits = pm_maxvaltobits(hammaxval);
  1247.  
  1248.     hamcode_red   = HAMCODE_RED << colbits;
  1249.     hamcode_green = HAMCODE_GREEN << colbits;
  1250.     hamcode_blue  = HAMCODE_BLUE << colbits;
  1251.  
  1252.     itoh = make_val_table(maxval, hammaxval);
  1253.  
  1254.     if( floyd )
  1255.         fi = ppm_fs_init(cols, maxval, 0);
  1256.  
  1257.     for( row = 0; row < rows; row++ ) {
  1258.         int noprev;
  1259.         int sr, sg, sb;         /* scaled values of current pixel */
  1260.         int ur, ug, ub;         /* unscaled values of current pixel */
  1261.         int spr, spg, spb;      /* scaled values of previous pixel */
  1262.         int upr, upg, upb;      /* unscaled values of previous pixel, for floyd */
  1263.         pixel *prow;
  1264.  
  1265.         noprev = 1;
  1266.         prow = next_pixrow(ifp, row);
  1267.         for( col = ppm_fs_startrow(fi, prow); col < cols; col = ppm_fs_next(fi, col) ) {
  1268.             pP = &prow[col];
  1269.  
  1270.             ur = PPM_GETR(*pP); ug = PPM_GETG(*pP); ub = PPM_GETB(*pP);
  1271.             sr = itoh[ur];      sg = itoh[ug];      sb = itoh[ub];
  1272.  
  1273.             i = ppm_lookupcolor(cht, pP);
  1274.             if( i == -1 ) {     /* no matching color in cmap, find closest match */
  1275.                 int ucr, ucg, ucb;  /* unscaled values of colormap entry */
  1276.  
  1277.                 if(  hammapmode == HAMMODE_GRAY ) {
  1278.                     if( maxval <= 255 ) /* Use fast approximation to 0.299 r + 0.587 g + 0.114 b. */
  1279.                         i = (int)((times77[ur] + times150[ug] + times29[ub] + 128) >> 8);
  1280.                     else /* Can't use fast approximation, so fall back on floats. */
  1281.                         i = (int)(PPM_LUMIN(*pP) + 0.5); /* -IUW added '+ 0.5' */
  1282.                     i = itoh[i];
  1283.                 }
  1284.                 else {
  1285.                     i = ppm_lookupcolor(cht2, pP);
  1286.                     if( i == -1 ) {
  1287.                         i = ppm_findclosestcolor(colormap, colors, pP);
  1288.                         if( usehash ) {
  1289.                             if( ppm_addtocolorhash(cht2, pP, i) < 0 ) {
  1290.                                 pm_message("out of memory adding to hash table, proceeding without it");
  1291.                                 usehash = 0;
  1292.                             }
  1293.                         }
  1294.                     }
  1295.                 }
  1296.                 ucr = PPM_GETR(colormap[i]); ucg = PPM_GETG(colormap[i]); ucb = PPM_GETB(colormap[i]);
  1297.  
  1298.                 if( noprev ) {  /* no previous pixel, must use colormap */
  1299.                     raw_rowbuf[col] = i;    /* + (HAMCODE_CMAP << colbits) */
  1300.                     upr = ucr;          upg = ucg;          upb = ucb;
  1301.                     spr = itoh[upr];    spg = itoh[upg];    spb = itoh[upb];
  1302.                     noprev = 0;
  1303.                 }
  1304.                 else {
  1305.                     register long di, dr, dg, db;
  1306.                     int scr, scg, scb;      /* scaled values of colormap entry */
  1307.  
  1308.                     scr = itoh[ucr]; scg = itoh[ucg]; scb = itoh[ucb];
  1309.  
  1310.                     /* compute distances for the four options */
  1311. #if 1
  1312.                     dr = abs(sg - spg) + abs(sb - spb);
  1313.                     dg = abs(sr - spr) + abs(sb - spb);
  1314.                     db = abs(sr - spr) + abs(sg - spg);
  1315.                     di = abs(sr - scr) + abs(sg - scg) + abs(sb - scb);
  1316. #else
  1317.                     dr = (sg - spg)*(sg - spg) + (sb - spb)*(sb - spb);
  1318.                     dg = (sr - spr)*(sr - spr) + (sb - spb)*(sb - spb);
  1319.                     db = (sr - spr)*(sr - spr) + (sg - spg)*(sg - spg);
  1320.                     di = (sr - scr)*(sr - scr) + (sg - scg)*(sg - scg) + (sb - scb)*(sb - scb);
  1321. #endif
  1322.  
  1323.                     if( di <= dr && di <= dg && di <= db ) {    /* prefer colormap lookup */
  1324.                         raw_rowbuf[col] = i;    /* + (HAMCODE_CMAP << colbits) */
  1325.                         upr = ucr;  upg = ucg;  upb = ucb;
  1326.                         spr = scr;  spg = scg;  spb = scb;
  1327.                     }
  1328.                     else
  1329.                     if( db <= dr && db <= dg ) {
  1330.                         raw_rowbuf[col] = sb + hamcode_blue;    /* + (HAMCODE_BLUE << colbits); */
  1331.                         spb = sb;
  1332.                         upb = ub;
  1333.                     }
  1334.                     else
  1335.                     if( dr <= dg ) {
  1336.                         raw_rowbuf[col] = sr + hamcode_red;     /* + (HAMCODE_RED << colbits); */
  1337.                         spr = sr;
  1338.                         upr = ur;
  1339.                     }
  1340.                     else {
  1341.                         raw_rowbuf[col] = sg + hamcode_green;   /* + (HAMCODE_GREEN << colbits); */
  1342.                         spg = sg;
  1343.                         upg = ug;
  1344.                     }
  1345.                 }
  1346.             }
  1347.             else {  /* prefect match in cmap */
  1348.                 raw_rowbuf[col] = i;    /* + (HAMCODE_CMAP << colbits) */
  1349.                 upr = PPM_GETR(colormap[i]); upg = PPM_GETG(colormap[i]); upb = PPM_GETB(colormap[i]);
  1350.                 spr = itoh[upr];            spg = itoh[upg];            spb = itoh[upb];
  1351.             }
  1352.             ppm_fs_update3(fi, col, upr, upg, upb);
  1353.         }
  1354.         bodysize += encode_row(ofp, raw_rowbuf, cols, nPlanes);
  1355.         if( maskmethod == mskHasMask )
  1356.             bodysize += encode_maskrow(ofp, raw_rowbuf, cols);
  1357.         ppm_fs_endrow(fi);
  1358.     }
  1359.     if( ofp && odd(bodysize) )
  1360.         put_byte(0);
  1361.  
  1362.     free(itoh);
  1363.  
  1364.     /* clean up */
  1365.     free(raw_rowbuf);
  1366.     ppm_fs_free(fi);
  1367.  
  1368.     return bodysize;
  1369. }
  1370.  
  1371.  
  1372. /************ deep (24-bit) ************/
  1373.  
  1374. static long do_deep_body      ARGS((FILE *ifp, FILE *ofp, int cols, int rows, pixval maxval, int bitspercolor));
  1375.  
  1376. static void
  1377. ppm_to_deep(fp, cols, rows, maxval, bitspercolor)
  1378.     FILE *fp;
  1379.     int cols, rows, maxval, bitspercolor;
  1380. {
  1381.     int nPlanes;
  1382.     long bodysize, oldsize, formsize;
  1383.  
  1384.     if( maskmethod == mskHasTransparentColor ) {
  1385.         pm_message("masking method \"%s\" not usable with deep ILBM - using \"%s\" instead",
  1386.                     mskNAME[mskHasTransparentColor], mskNAME[mskHasMask]);
  1387.         maskmethod = mskHasMask;
  1388.     }
  1389.  
  1390.     nPlanes = 3*bitspercolor;
  1391.  
  1392.     bodysize = oldsize = rows * TOTALPLANES(nPlanes) * RowBytes(cols);
  1393.     if( DO_COMPRESS ) {
  1394.         bodysize = do_deep_body(fp, NULL, cols, rows, maxval, bitspercolor);
  1395.         if( bodysize > oldsize )
  1396.             pm_message("warning - %s compression increases BODY size by %d%%", cmpNAME[compmethod], 100*(bodysize-oldsize)/oldsize);
  1397.         else
  1398.             pm_message("BODY compression (%s): %d%%", cmpNAME[compmethod], 100*(oldsize-bodysize)/oldsize);
  1399. #if 0
  1400.         if( bodysize > oldsize && !compr_force ) {
  1401.             pm_message("%s compression would increase body size by %d%%", cmpNAME[compmethod], 100*(bodysize-oldsize)/oldsize);
  1402.             pm_message("writing uncompressed image");
  1403.             compmethod = cmpNone;
  1404.             bodysize = oldsize;
  1405.         }
  1406. #endif
  1407.     }
  1408.  
  1409.  
  1410.     formsize =
  1411.         4 +                                 /* ILBM */
  1412.         4 + 4 + BitMapHeaderSize +          /* BMHD size header */
  1413.         4 + 4 + bodysize + PAD(bodysize) +  /* BODY size data */
  1414.         length_of_text_chunks();
  1415.     if( gen_camg )
  1416.         formsize += 4 + 4 + CAMGChunkSize;  /* CAMG size viewportmodes */
  1417.  
  1418.     put_big_long(ID_FORM);
  1419.     put_big_long(formsize);
  1420.     put_big_long(ID_ILBM);
  1421.  
  1422.     write_bmhd(cols, rows, nPlanes);
  1423.     write_text_chunks();
  1424.     if( gen_camg )
  1425.         write_camg();
  1426.  
  1427.     /* write body */
  1428.     put_big_long(ID_BODY);
  1429.     put_big_long(bodysize);
  1430.     if( DO_COMPRESS )
  1431.         write_body_rows();
  1432.     else
  1433.         do_deep_body(fp, stdout, cols, rows, maxval, bitspercolor);
  1434. }
  1435.  
  1436.  
  1437. static long
  1438. #if __STDC__
  1439. do_deep_body(FILE *ifp, FILE *ofp, int cols, int rows, pixval maxval, int bitspercolor)
  1440. #else
  1441. do_deep_body(ifp, ofp, cols, rows, maxval, bitspercolor)
  1442.     FILE *ifp, *ofp;
  1443.     int cols, rows;
  1444.     pixval maxval;
  1445.     int bitspercolor;
  1446. #endif
  1447. {
  1448.     register int row, col;
  1449.     pixel *pP;
  1450.     int *table = NULL;
  1451.     long bodysize = 0;
  1452.     rawtype *redbuf, *greenbuf, *bluebuf;
  1453.     int newmaxval;
  1454.  
  1455.     redbuf   = MALLOC(cols, rawtype);
  1456.     greenbuf = MALLOC(cols, rawtype);
  1457.     bluebuf  = MALLOC(cols, rawtype);
  1458.  
  1459.     newmaxval = pm_bitstomaxval(bitspercolor);
  1460.     if( maxval != newmaxval ) {
  1461.         pm_message("maxval is not %d - automatically rescaling colors", newmaxval);
  1462.         table = make_val_table(maxval, newmaxval);
  1463.     }
  1464.  
  1465.     for( row = 0; row < rows; row++ ) {
  1466.         pP = next_pixrow(ifp, row);
  1467.         if( table ) {
  1468.             for( col = 0; col < cols; col++, pP++ ) {
  1469.                 redbuf[col]     = table[PPM_GETR(*pP)];
  1470.                 greenbuf[col]   = table[PPM_GETG(*pP)];
  1471.                 bluebuf[col]    = table[PPM_GETB(*pP)];
  1472.             }
  1473.         }
  1474.         else {
  1475.             for( col = 0; col < cols; col++, pP++ ) {
  1476.                 redbuf[col]     = PPM_GETR(*pP);
  1477.                 greenbuf[col]   = PPM_GETG(*pP);
  1478.                 bluebuf[col]    = PPM_GETB(*pP);
  1479.             }
  1480.         }
  1481.         bodysize += encode_row(ofp, redbuf,   cols, bitspercolor);
  1482.         bodysize += encode_row(ofp, greenbuf, cols, bitspercolor);
  1483.         bodysize += encode_row(ofp, bluebuf,  cols, bitspercolor);
  1484.         if( maskmethod == mskHasMask )
  1485.             bodysize += encode_maskrow(ofp, redbuf, cols);
  1486.     }
  1487.     if( ofp && odd(bodysize) )
  1488.         put_byte(0);
  1489.  
  1490.     /* clean up */
  1491.     if( table )
  1492.         free(table);
  1493.     free(redbuf);
  1494.     free(greenbuf);
  1495.     free(bluebuf);
  1496.  
  1497.     return bodysize;
  1498. }
  1499.  
  1500.  
  1501. /************ direct color ************/
  1502.  
  1503. static long do_dcol_body      ARGS((FILE *ifp, FILE *ofp, int cols, int rows, pixval maxval, DirectColor *dcol));
  1504.  
  1505. static void
  1506. ppm_to_dcol(fp, cols, rows, maxval, dcol)
  1507.     FILE *fp;
  1508.     int cols, rows, maxval;
  1509.     DirectColor *dcol;
  1510. {
  1511.     int nPlanes;
  1512.     long bodysize, oldsize, formsize;
  1513.  
  1514.     if( maskmethod == mskHasTransparentColor ) {
  1515.         pm_message("masking method \"%s\" not usable with deep ILBM - using \"%s\" instead",
  1516.                     mskNAME[mskHasTransparentColor], mskNAME[mskHasMask]);
  1517.         maskmethod = mskHasMask;
  1518.     }
  1519.  
  1520.     nPlanes = dcol->r + dcol->g + dcol->b;
  1521.  
  1522.     bodysize = oldsize = rows * TOTALPLANES(nPlanes) * RowBytes(cols);
  1523.     if( DO_COMPRESS ) {
  1524.         bodysize = do_dcol_body(fp, NULL, cols, rows, maxval, dcol);
  1525.         if( bodysize > oldsize )
  1526.             pm_message("warning - %s compression increases BODY size by %d%%", cmpNAME[compmethod], 100*(bodysize-oldsize)/oldsize);
  1527.         else
  1528.             pm_message("BODY compression (%s): %d%%", cmpNAME[compmethod], 100*(oldsize-bodysize)/oldsize);
  1529. #if 0
  1530.         if( bodysize > oldsize && !compr_force ) {
  1531.             pm_message("%s compression would increase body size by %d%%", cmpNAME[compmethod], 100*(bodysize-oldsize)/oldsize);
  1532.             pm_message("writing uncompressed image");
  1533.             compmethod = cmpNone;
  1534.             bodysize = oldsize;
  1535.         }
  1536. #endif
  1537.     }
  1538.  
  1539.  
  1540.     formsize =
  1541.         4 +                                 /* ILBM */
  1542.         4 + 4 + BitMapHeaderSize +          /* BMHD size header */
  1543.         4 + 4 + DirectColorSize +           /* DCOL size dcol */
  1544.         4 + 4 + bodysize + PAD(bodysize) +  /* BODY size data */
  1545.         length_of_text_chunks();
  1546.     if( gen_camg )
  1547.         formsize += 4 + 4 + CAMGChunkSize;  /* CAMG size viewportmodes */
  1548.  
  1549.     put_big_long(ID_FORM);
  1550.     put_big_long(formsize);
  1551.     put_big_long(ID_ILBM);
  1552.  
  1553.     write_bmhd(cols, rows, nPlanes);
  1554.     write_text_chunks();
  1555.  
  1556.     put_big_long(ID_DCOL);
  1557.     put_big_long(DirectColorSize);
  1558.     put_byte(dcol->r);
  1559.     put_byte(dcol->g);
  1560.     put_byte(dcol->b);
  1561.     put_byte(0);    /* pad */
  1562.  
  1563.     if( gen_camg )
  1564.         write_camg();
  1565.  
  1566.     /* write body */
  1567.     put_big_long(ID_BODY);
  1568.     put_big_long(bodysize);
  1569.     if( DO_COMPRESS )
  1570.         write_body_rows();
  1571.     else
  1572.         do_dcol_body(fp, stdout, cols, rows, maxval, dcol);
  1573. }
  1574.  
  1575.  
  1576. static long
  1577. #if __STDC__
  1578. do_dcol_body(FILE *ifp, FILE *ofp, int cols, int rows, pixval maxval, DirectColor *dcol)
  1579. #else
  1580. do_dcol_body(ifp, ofp, cols, rows, maxval, dcol)
  1581.     FILE *ifp, *ofp;
  1582.     int cols, rows;
  1583.     pixval maxval;
  1584.     DirectColor *dcol;
  1585. #endif
  1586. {
  1587.     register int row, col;
  1588.     pixel *pP;
  1589.     long bodysize = 0;
  1590.     rawtype *redbuf, *greenbuf, *bluebuf;
  1591.     int *redtable, *greentable, *bluetable;
  1592.  
  1593.     redbuf   = MALLOC(cols, rawtype);
  1594.     greenbuf = MALLOC(cols, rawtype);
  1595.     bluebuf  = MALLOC(cols, rawtype);
  1596.  
  1597.     redtable   = make_val_table(maxval, pm_bitstomaxval(dcol->r));
  1598.     greentable = make_val_table(maxval, pm_bitstomaxval(dcol->g));
  1599.     bluetable  = make_val_table(maxval, pm_bitstomaxval(dcol->b));
  1600.  
  1601. /***
  1602.     newmaxval = pm_bitstomaxval(bitspercolor);
  1603.     if( maxval != newmaxval ) {
  1604.         pm_message("maxval is not %d - automatically rescaling colors", newmaxval);
  1605.         table = make_val_table(maxval, newmaxval);
  1606.     }
  1607. ***/
  1608.  
  1609.     for( row = 0; row < rows; row++ ) {
  1610.         pP = next_pixrow(ifp, row);
  1611.         for( col = 0; col < cols; col++, pP++ ) {
  1612.             redbuf[col]   = redtable[PPM_GETR(*pP)];
  1613.             greenbuf[col] = greentable[PPM_GETG(*pP)];
  1614.             bluebuf[col]  = bluetable[PPM_GETB(*pP)];
  1615.         }
  1616.         bodysize += encode_row(ofp, redbuf,   cols, dcol->r);
  1617.         bodysize += encode_row(ofp, greenbuf, cols, dcol->g);
  1618.         bodysize += encode_row(ofp, bluebuf,  cols, dcol->b);
  1619.         if( maskmethod == mskHasMask )
  1620.             bodysize += encode_maskrow(ofp, redbuf, cols);
  1621.     }
  1622.     if( ofp && odd(bodysize) )
  1623.         put_byte(0);
  1624.  
  1625.     /* clean up */
  1626.     free(redtable);
  1627.     free(greentable);
  1628.     free(bluetable);
  1629.     free(redbuf);
  1630.     free(greenbuf);
  1631.     free(bluebuf);
  1632.  
  1633.     return bodysize;
  1634. }
  1635.  
  1636.  
  1637. /************ normal colormapped ************/
  1638.  
  1639. static long do_std_body     ARGS((FILE *ifp, FILE *ofp, int cols, int rows, pixval maxval, pixel *colormap, int colors, int nPlanes));
  1640.  
  1641. static void
  1642. ppm_to_std(fp, cols, rows, maxval, colormap, colors, cmapmaxval, maxcolors, nPlanes)
  1643.     FILE *fp;
  1644.     int cols, rows, maxval;
  1645.     pixel *colormap;
  1646.     int cmapmaxval, colors, maxcolors, nPlanes;
  1647. {
  1648.     long formsize, cmapsize, bodysize, oldsize;
  1649.  
  1650.     if( maskmethod == mskHasTransparentColor ) {
  1651.         if( transpColor ) {
  1652.             int oldcolors = colors;
  1653.             transpIndex = ppm_addtocolorrow(colormap, &colors, maxcolors, transpColor);
  1654.         }
  1655.         else
  1656.         if( colors < maxcolors )
  1657.             transpIndex = colors;
  1658.  
  1659.         if( transpIndex < 0 ) {
  1660.             pm_message("too many colors for masking method \"%s\" - using \"%s\" instead",
  1661.                         mskNAME[mskHasTransparentColor], mskNAME[mskHasMask]);
  1662.             maskmethod = mskHasMask;
  1663.         }
  1664.     }
  1665.  
  1666.     if( cmapmaxval != maxval ) {
  1667.         int i, *table;
  1668.         pixel *newcmap;
  1669.  
  1670.         table = make_val_table(cmapmaxval, maxval);
  1671.         for( i = 0; i < colors; i++ )
  1672.             PPM_ASSIGN(newcmap[i], table[PPM_GETR(colormap[i])], table[PPM_GETG(colormap[i])], table[PPM_GETB(colormap[i])]);
  1673.         free(table);
  1674.         colormap = newcmap;
  1675.     }
  1676.     if( sortcmap )
  1677.         ppm_sortcolorrow(colormap, colors, PPM_STDSORT);
  1678.  
  1679.     bodysize = oldsize = rows * TOTALPLANES(nPlanes) * RowBytes(cols);
  1680.     if( DO_COMPRESS ) {
  1681.         bodysize = do_std_body(fp, NULL, cols, rows, maxval, colormap, colors, nPlanes);
  1682.         if( bodysize > oldsize )
  1683.             pm_message("warning - %s compression increases BODY size by %d%%", cmpNAME[compmethod], 100*(bodysize-oldsize)/oldsize);
  1684.         else
  1685.             pm_message("BODY compression (%s): %d%%", cmpNAME[compmethod], 100*(oldsize-bodysize)/oldsize);
  1686. #if 0
  1687.         if( bodysize > oldsize && !compr_force ) {
  1688.             pm_message("%s compression would increase body size by %d%%", cmpNAME[compmethod], 100*(bodysize-oldsize)/oldsize);
  1689.             pm_message("writing uncompressed image");
  1690.             compmethod = cmpNone;
  1691.             bodysize = oldsize;
  1692.         }
  1693. #endif
  1694.     }
  1695.  
  1696.     cmapsize = colors * 3;
  1697.  
  1698.     formsize =
  1699.         4 +                                 /* ILBM */
  1700.         4 + 4 + BitMapHeaderSize +          /* BMHD size header */
  1701.         4 + 4 + cmapsize + PAD(cmapsize) +  /* CMAP size colormap */
  1702.         4 + 4 + bodysize + PAD(bodysize) +  /* BODY size data */
  1703.         length_of_text_chunks();
  1704.     if( gen_camg )
  1705.         formsize += 4 + 4 + CAMGChunkSize;  /* CAMG size viewportmodes */
  1706.  
  1707.     put_big_long(ID_FORM);
  1708.     put_big_long(formsize);
  1709.     put_big_long(ID_ILBM);
  1710.  
  1711.     write_bmhd(cols, rows, nPlanes);
  1712.     write_text_chunks();
  1713.     if( gen_camg )
  1714.         write_camg();
  1715.     write_cmap(colormap, colors, maxval);
  1716.  
  1717.     /* write body */
  1718.     put_big_long(ID_BODY);
  1719.     put_big_long(bodysize);
  1720.     if( DO_COMPRESS )
  1721.         write_body_rows();
  1722.     else
  1723.         do_std_body(fp, stdout, cols, rows, maxval, colormap, colors, nPlanes);
  1724. }
  1725.  
  1726.  
  1727. static long
  1728. #if __STDC__
  1729. do_std_body(FILE *ifp, FILE *ofp, int cols, int rows, pixval maxval,
  1730.             pixel *colormap, int colors, int nPlanes)
  1731. #else
  1732. do_std_body(ifp, ofp, cols, rows, maxval, colormap, colors, nPlanes)
  1733.     FILE *ifp, *ofp;
  1734.     int cols, rows;
  1735.     pixval maxval;
  1736.     pixel *colormap;
  1737.     int colors;
  1738.     int nPlanes;
  1739. #endif
  1740. {
  1741.     register int row, col, i;
  1742.     pixel *pP;
  1743.     rawtype *raw_rowbuf;
  1744.     ppm_fs_info *fi = NULL;
  1745.     long bodysize = 0;
  1746.     int usehash = 1;
  1747.     colorhash_table cht;
  1748.  
  1749.     raw_rowbuf = MALLOC(cols, rawtype);
  1750.     cht = ppm_colorrowtocolorhash(colormap, colors);
  1751.     if( floyd )
  1752.         fi = ppm_fs_init(cols, maxval, FS_ALTERNATE);
  1753.  
  1754.     for( row = 0; row < rows; row++ ) {
  1755.         pixel *prow;
  1756.         prow = next_pixrow(ifp, row);
  1757.  
  1758.         for( col = ppm_fs_startrow(fi, prow); col < cols; col = ppm_fs_next(fi, col) ) {
  1759.             pP = &prow[col];
  1760.  
  1761.             if( maskmethod == mskHasTransparentColor && maskrow[col] == PBM_WHITE )
  1762.                 i = transpIndex;
  1763.             else {
  1764.                 /* Check hash table to see if we have already matched this color. */
  1765.                 i = ppm_lookupcolor(cht, pP);
  1766.                 if( i == -1 ) {
  1767.                     i = ppm_findclosestcolor(colormap, colors, pP);    /* No; search colormap for closest match. */
  1768.                     if( usehash ) {
  1769.                         if( ppm_addtocolorhash(cht, pP, i) < 0 ) {
  1770.                             pm_message("out of memory adding to hash table, proceeding without it");
  1771.                             usehash = 0;
  1772.                         }
  1773.                     }
  1774.                 }
  1775.             }
  1776.             raw_rowbuf[col] = i;
  1777.             ppm_fs_update(fi, col, &colormap[i]);
  1778.         }
  1779.         bodysize += encode_row(ofp, raw_rowbuf, cols, nPlanes);
  1780.         if( maskmethod == mskHasMask )
  1781.             bodysize += encode_maskrow(ofp, raw_rowbuf, cols);
  1782.         ppm_fs_endrow(fi);
  1783.     }
  1784.     if( ofp && odd(bodysize) )
  1785.         put_byte(0);
  1786.  
  1787.     /* clean up */
  1788.     ppm_freecolorhash(cht);
  1789.     free(raw_rowbuf);
  1790.     ppm_fs_free(fi);
  1791.  
  1792.     return bodysize;
  1793. }
  1794.  
  1795. /************ RGB8 ************/
  1796.  
  1797. static void
  1798. ppm_to_rgb8(ifp, cols, rows, maxval)
  1799.     FILE *ifp;
  1800.     int cols, rows;
  1801.     int maxval;
  1802. {
  1803.     long bodysize, oldsize, formsize;
  1804.     pixel *pP;
  1805.     int *table = NULL;
  1806.     int row, col1, col2, compr_len, len;
  1807.     unsigned char *compr_row;
  1808.  
  1809.     maskmethod = 0;     /* no masking - RGB8 uses genlock bits */
  1810.     compmethod = 4;     /* RGB8 files are always compressed */
  1811.     compr_row = MALLOC(cols * 4, unsigned char);
  1812.  
  1813.     if( maxval != 255 ) {
  1814.         pm_message("maxval is not 255 - automatically rescaling colors");
  1815.         table = make_val_table(maxval, 255);
  1816.     }
  1817.  
  1818.     oldsize = cols * rows * 4;
  1819.     bodysize = 0;
  1820.     for( row = 0; row < rows; row++ ) {
  1821.         pP = next_pixrow(ifp, row);
  1822.         compr_len = 0;
  1823.         for( col1 = 0; col1 < cols; col1 = col2 ) {
  1824.             col2 = col1 + 1;
  1825.             if( maskrow ) {
  1826.                 while( col2 < cols && PPM_EQUAL(pP[col1], pP[col2]) && maskrow[col1] == maskrow[col2] )
  1827.                     col2++;
  1828.             }
  1829.             else {
  1830.                 while( col2 < cols && PPM_EQUAL(pP[col1], pP[col2]) )
  1831.                     col2++;
  1832.             }
  1833.             len = col2 - col1;
  1834.             while( len ) {
  1835.                 int count;
  1836.                 count = (len > 127 ? 127 : len);
  1837.                 len -= count;
  1838.                 if( table ) {
  1839.                     compr_row[compr_len++] = table[PPM_GETR(pP[col1])];
  1840.                     compr_row[compr_len++] = table[PPM_GETG(pP[col1])];
  1841.                     compr_row[compr_len++] = table[PPM_GETB(pP[col1])];
  1842.                 }
  1843.                 else {
  1844.                     compr_row[compr_len++] = PPM_GETR(pP[col1]);
  1845.                     compr_row[compr_len++] = PPM_GETG(pP[col1]);
  1846.                     compr_row[compr_len++] = PPM_GETB(pP[col1]);
  1847.                 }
  1848.                 compr_row[compr_len] = count;
  1849.                 if( maskrow && maskrow[col1] == PBM_WHITE )
  1850.                     compr_row[compr_len] |= 1<<7;     /* genlock bit */
  1851.                 ++compr_len;
  1852.             }
  1853.         }
  1854.         store_bodyrow(compr_row, compr_len);
  1855.         bodysize += compr_len;
  1856.     }
  1857.  
  1858.     pm_message("BODY compression: %d%%", 100*(oldsize-bodysize)/oldsize);
  1859.  
  1860.     formsize =
  1861.         4 +                                 /* RGB8 */
  1862.         4 + 4 + BitMapHeaderSize +          /* BMHD size header */
  1863.         4 + 4 + CAMGChunkSize +             /* CAMG size viewportmode */
  1864.         4 + 4 + bodysize + PAD(bodysize) +  /* BODY size data */
  1865.         length_of_text_chunks();
  1866.  
  1867.     /* write header */
  1868.     put_big_long(ID_FORM);
  1869.     put_big_long(formsize);
  1870.     put_big_long(ID_RGB8);
  1871.  
  1872.     write_bmhd(cols, rows, 25);
  1873.     write_text_chunks();
  1874.     write_camg();               /* RGB8 requires CAMG chunk */
  1875.  
  1876.     put_big_long(ID_BODY);
  1877.     put_big_long(bodysize);
  1878.     write_body_rows();
  1879. }
  1880.  
  1881.  
  1882. /************ RGBN ************/
  1883.  
  1884. static void
  1885. ppm_to_rgbn(ifp, cols, rows, maxval)
  1886.     FILE *ifp;
  1887.     int cols, rows;
  1888.     int maxval;
  1889. {
  1890.     long bodysize, oldsize, formsize;
  1891.     pixel *pP;
  1892.     int *table = NULL;
  1893.     int row, col1, col2, compr_len, len;
  1894.     unsigned char *compr_row;
  1895.  
  1896.     maskmethod = 0;     /* no masking - RGBN uses genlock bits */
  1897.     compmethod = 4;     /* RGBN files are always compressed */
  1898.     compr_row = MALLOC(cols * 2, unsigned char);
  1899.  
  1900.     if( maxval != 15 ) {
  1901.         pm_message("maxval is not 15 - automatically rescaling colors");
  1902.         table = make_val_table(maxval, 15);
  1903.     }
  1904.  
  1905.     oldsize = cols * rows * 2;
  1906.     bodysize = 0;
  1907.     for( row = 0; row < rows; row++ ) {
  1908.         pP = next_pixrow(ifp, row);
  1909.         compr_len = 0;
  1910.         for( col1 = 0; col1 < cols; col1 = col2 ) {
  1911.             col2 = col1 + 1;
  1912.             if( maskrow ) {
  1913.                 while( col2 < cols && PPM_EQUAL(pP[col1], pP[col2]) && maskrow[col1] == maskrow[col2] )
  1914.                     col2++;
  1915.             }
  1916.             else {
  1917.                 while( col2 < cols && PPM_EQUAL(pP[col1], pP[col2]) )
  1918.                     col2++;
  1919.             }
  1920.             len = col2 - col1;
  1921.             while( len ) {
  1922.                 int count;
  1923.                 count = (len > 65535 ? 65535 : len);
  1924.                 len -= count;
  1925.                 if( table ) {
  1926.                     compr_row[compr_len]  = table[PPM_GETR(pP[col1])] << 4;
  1927.                     compr_row[compr_len] |= table[PPM_GETG(pP[col1])];
  1928.                     ++compr_len;
  1929.                     compr_row[compr_len]  = table[PPM_GETB(pP[col1])] << 4;
  1930.                 }
  1931.                 else {
  1932.                     compr_row[compr_len]  = PPM_GETR(pP[col1]) << 4;
  1933.                     compr_row[compr_len] |= PPM_GETG(pP[col1]);
  1934.                     ++compr_len;
  1935.                     compr_row[compr_len]  = PPM_GETB(pP[col1]) << 4;
  1936.                 }
  1937.                 if( maskrow && maskrow[col1] == PBM_WHITE )
  1938.                     compr_row[compr_len] |= 1<<3;   /* genlock bit */
  1939.                 if( count <= 7 )
  1940.                     compr_row[compr_len++] |= count;                    /* 3 bit repeat count */
  1941.                 else {
  1942.                     ++compr_len;                                        /* 3 bit repeat count = 0 */
  1943.                     if( count <= 255 )
  1944.                         compr_row[compr_len++] = (unsigned char)count;  /* byte repeat count */
  1945.                     else {
  1946.                         compr_row[compr_len++] = (unsigned char)0;      /* byte repeat count = 0 */
  1947.                         compr_row[compr_len++] = (count >> 8) & 0xff;   /* word repeat count MSB */
  1948.                         compr_row[compr_len++] = count & 0xff;          /* word repeat count LSB */
  1949.                     }
  1950.                 }
  1951.             }
  1952.         }
  1953.         store_bodyrow(compr_row, compr_len);
  1954.         bodysize += compr_len;
  1955.     }
  1956.  
  1957.     pm_message("BODY compression: %d%%", 100*(oldsize-bodysize)/oldsize);
  1958.  
  1959.     formsize =
  1960.         4 +                                 /* RGBN */
  1961.         4 + 4 + BitMapHeaderSize +          /* BMHD size header */
  1962.         4 + 4 + CAMGChunkSize +             /* CAMG size viewportmode */
  1963.         4 + 4 + bodysize + PAD(bodysize) +  /* BODY size data */
  1964.         length_of_text_chunks();
  1965.  
  1966.     /* write header */
  1967.     put_big_long(ID_FORM);
  1968.     put_big_long(formsize);
  1969.     put_big_long(ID_RGBN);
  1970.  
  1971.     write_bmhd(cols, rows, 13);
  1972.     write_text_chunks();
  1973.     write_camg();               /* RGBN requires CAMG chunk */
  1974.  
  1975.     put_big_long(ID_BODY);
  1976.     put_big_long(bodysize);
  1977.     write_body_rows();
  1978. }
  1979.  
  1980.  
  1981. /************ multipalette ************/
  1982.  
  1983. #ifdef ILBM_PCHG
  1984. static pixel *ppmslice[2];  /* need 2 for laced ILBMs, else 1 */
  1985.  
  1986. void ppm_to_pchg()
  1987. {
  1988. /*
  1989.     read first slice
  1990.     build a colormap from this slice
  1991.     select upto <maxcolors> colors
  1992.     build colormap from selected colors
  1993.     map slice to colormap
  1994.     write slice
  1995.     while( !finished ) {
  1996.         read next slice
  1997.         compute distances for each pixel and select upto
  1998.             <maxchangesperslice> unused colors in this slice
  1999.         modify selected colors to the ones with maximum(?) distance
  2000.         map slice to colormap
  2001.         write slice
  2002.     }
  2003.  
  2004.  
  2005.     for HAM use a different mapping:
  2006.         compute distance to closest color in colormap
  2007.         if( there is no matching color in colormap ) {
  2008.             compute distances for the three "modify" cases
  2009.             use the shortest distance from the four cases
  2010.         }
  2011. */
  2012. }
  2013. #endif
  2014.  
  2015.  
  2016. /************ ILBM functions ************/
  2017.  
  2018. static int
  2019. length_of_text_chunks ARGS((void))
  2020. {
  2021.     int len, n;
  2022.  
  2023.     len = 0;
  2024.     if( anno_chunk ) {
  2025.         n = strlen(anno_chunk);
  2026.         len += 4 + 4 + n + PAD(n);      /* ID chunksize text */
  2027.     }
  2028.     if( auth_chunk ) {
  2029.         n = strlen(auth_chunk);
  2030.         len += 4 + 4 + n + PAD(n);      /* ID chunksize text */
  2031.     }
  2032.     if( name_chunk ) {
  2033.         n = strlen(name_chunk);
  2034.         len += 4 + 4 + n + PAD(n);      /* ID chunksize text */
  2035.     }
  2036.     if( copyr_chunk ) {
  2037.         n = strlen(copyr_chunk);
  2038.         len += 4 + 4 + n + PAD(n);      /* ID chunksize text */
  2039.     }
  2040.     if( text_chunk ) {
  2041.         n = strlen(text_chunk);
  2042.         len += 4 + 4 + n + PAD(n);      /* ID chunksize text */
  2043.     }
  2044.     return len;
  2045. }
  2046.  
  2047.  
  2048. static void
  2049. write_text_chunks ARGS((void))
  2050. {
  2051.     int n;
  2052.  
  2053.     if( anno_chunk ) {
  2054.         n = strlen(anno_chunk);
  2055.         put_big_long(ID_ANNO);
  2056.         put_big_long(n);
  2057.         write_bytes((unsigned char *)anno_chunk, n);
  2058.         if( odd(n) )
  2059.             put_byte(0);
  2060.     }
  2061.     if( auth_chunk ) {
  2062.         n = strlen(auth_chunk);
  2063.         put_big_long(ID_AUTH);
  2064.         put_big_long(n);
  2065.         write_bytes((unsigned char *)auth_chunk, n);
  2066.         if( odd(n) )
  2067.             put_byte(0);
  2068.     }
  2069.     if( copyr_chunk ) {
  2070.         n = strlen(copyr_chunk);
  2071.         put_big_long(ID_copy);
  2072.         put_big_long(n);
  2073.         write_bytes((unsigned char *)copyr_chunk, n);
  2074.         if( odd(n) )
  2075.             put_byte(0);
  2076.     }
  2077.     if( name_chunk ) {
  2078.         n = strlen(name_chunk);
  2079.         put_big_long(ID_NAME);
  2080.         put_big_long(n);
  2081.         write_bytes((unsigned char *)name_chunk, n);
  2082.         if( odd(n) )
  2083.             put_byte(0);
  2084.     }
  2085.     if( text_chunk ) {
  2086.         n = strlen(text_chunk);
  2087.         put_big_long(ID_TEXT);
  2088.         put_big_long(n);
  2089.         write_bytes((unsigned char *)text_chunk, n);
  2090.         if( odd(n) )
  2091.             put_byte(0);
  2092.     }
  2093. }
  2094.  
  2095.  
  2096. static void
  2097. write_cmap(colormap, colors, maxval)
  2098.     pixel *colormap;
  2099.     int colors, maxval;
  2100. {
  2101.     int cmapsize, i;
  2102.  
  2103.     cmapsize = 3 * colors;
  2104.  
  2105.     /* write colormap */
  2106.     put_big_long(ID_CMAP);
  2107.     put_big_long(cmapsize);
  2108.     if( maxval != MAXCOLVAL ) {
  2109.         int *table;
  2110.         pm_message("maxval is not %d - automatically rescaling colors", MAXCOLVAL);
  2111.         table = make_val_table(maxval, MAXCOLVAL);
  2112.         for( i = 0; i < colors; i++ ) {
  2113.             put_byte(table[PPM_GETR(colormap[i])]);
  2114.             put_byte(table[PPM_GETG(colormap[i])]);
  2115.             put_byte(table[PPM_GETB(colormap[i])]);
  2116.         }
  2117.         free(table);
  2118.     }
  2119.     else {
  2120.         for( i = 0; i < colors; i++ ) {
  2121.             put_byte(PPM_GETR(colormap[i]));
  2122.             put_byte(PPM_GETG(colormap[i]));
  2123.             put_byte(PPM_GETB(colormap[i]));
  2124.         }
  2125.     }
  2126.     if( odd(cmapsize) )
  2127.         put_byte(0);
  2128. }
  2129.  
  2130.  
  2131. static void
  2132. write_bmhd(cols, rows, nPlanes)
  2133.     int cols, rows, nPlanes;
  2134. {
  2135.     unsigned char xasp = 10, yasp = 10;
  2136.  
  2137.     if( viewportmodes & vmLACE )
  2138.         xasp *= 2;
  2139.     if( viewportmodes & vmHIRES )
  2140.         yasp *= 2;
  2141.  
  2142.     put_big_long(ID_BMHD);
  2143.     put_big_long(BitMapHeaderSize);
  2144.  
  2145.     put_big_short(cols);
  2146.     put_big_short(rows);
  2147.     put_big_short(0);                       /* x-offset */
  2148.     put_big_short(0);                       /* y-offset */
  2149.     put_byte(nPlanes);                      /* no of planes */
  2150.     put_byte(maskmethod);                   /* masking */
  2151.     put_byte(compmethod);                   /* compression */
  2152.     put_byte(BMHD_FLAGS_CMAPOK);            /* flags */
  2153.     if( maskmethod == mskHasTransparentColor )
  2154.         put_big_short(transpIndex);
  2155.     else
  2156.         put_big_short(0);
  2157.     put_byte(xasp);                         /* x-aspect */
  2158.     put_byte(yasp);                         /* y-aspect */
  2159.     put_big_short(cols);                    /* pageWidth */
  2160.     put_big_short(rows);                    /* pageHeight */
  2161. }
  2162.  
  2163.  
  2164. /* encode algorithm by Johan Widen (jw@jwdata.se) */
  2165. static const unsigned char bitmask[] = {1, 2, 4, 8, 16, 32, 64, 128};
  2166.  
  2167. static long
  2168. encode_row(outfile, rawrow, cols, nPlanes)
  2169.     FILE *outfile;  /* if non-NULL, write uncompressed row to this file */
  2170.     rawtype *rawrow;
  2171.     int cols, nPlanes;
  2172. {
  2173.     int plane, bytes;
  2174.     long retbytes = 0;
  2175.  
  2176.     bytes = RowBytes(cols);
  2177.  
  2178.     /* Encode and write raw bytes in plane-interleaved form. */
  2179.     for( plane = 0; plane < nPlanes; plane++ ) {
  2180.         register int col, cbit;
  2181.         register rawtype *rp;
  2182.         register unsigned char *cp;
  2183.         int mask;
  2184.  
  2185.         mask = 1 << plane;
  2186.         cbit = -1;
  2187.         cp = coded_rowbuf-1;
  2188.         rp = rawrow;
  2189.         for( col = 0; col < cols; col++, cbit--, rp++ ) {
  2190.             if( cbit < 0 ) {
  2191.                 cbit = 7;
  2192.                 *++cp = 0;
  2193.             }
  2194.             if( *rp & mask )
  2195.                 *cp |= bitmask[cbit];
  2196.         }
  2197.         if( outfile ) {
  2198.             write_bytes(coded_rowbuf, bytes);
  2199.             retbytes += bytes;
  2200.         }
  2201.         else
  2202.             retbytes += compress_row(bytes);
  2203.     }
  2204.     return retbytes;
  2205. }
  2206.  
  2207.  
  2208. static long
  2209. encode_maskrow(ofp, rawrow, cols)
  2210.     FILE *ofp;
  2211.     rawtype *rawrow;
  2212.     int cols;
  2213. {
  2214.     int col;
  2215.  
  2216.     for( col = 0; col < cols; col++ ) {
  2217.         if( maskrow[col] == PBM_BLACK )
  2218.             rawrow[col] = 1;
  2219.         else
  2220.             rawrow[col] = 0;
  2221.     }
  2222.     return encode_row(ofp, rawrow, cols, 1);
  2223. }
  2224.  
  2225.  
  2226. static int
  2227. compress_row(bytes)
  2228.     int bytes;
  2229. {
  2230.     int newbytes;
  2231.  
  2232.     switch( compmethod ) {
  2233.         case cmpByteRun1:
  2234.             newbytes = runbyte1(bytes);
  2235.             break;
  2236.         default:
  2237.             pm_error("compress_row(): unknown compression method %d\n", compmethod);
  2238.     }
  2239.     store_bodyrow(compr_rowbuf, newbytes);
  2240.  
  2241.     return newbytes;
  2242. }
  2243.  
  2244.  
  2245. static void
  2246. store_bodyrow(row, len)
  2247.     unsigned char *row;
  2248.     int len;
  2249. {
  2250.     int idx = cur_block->used;
  2251.     if( idx >= ROWS_PER_BLOCK ) {
  2252.         cur_block->next = MALLOC(1, bodyblock);
  2253.         cur_block = cur_block->next;
  2254.         cur_block->used = idx = 0;
  2255.         cur_block->next = NULL;
  2256.     }
  2257.     cur_block->row[idx] = MALLOC(len, unsigned char);
  2258.     cur_block->len[idx] = len;
  2259.     bcopy(row, cur_block->row[idx], len);
  2260.     cur_block->used++;
  2261. }
  2262.  
  2263.  
  2264. static void
  2265. write_body_rows ARGS((void))
  2266. {
  2267.     bodyblock *b;
  2268.     int i;
  2269.     long total = 0;
  2270.  
  2271.     for( b = &firstblock; b != NULL; b = b->next ) {
  2272.         for( i = 0; i < b->used; i++ ) {
  2273.             write_bytes(b->row[i], b->len[i]);
  2274.             total += b->len[i];
  2275.         }
  2276.     }
  2277.     if( odd(total) )
  2278.         put_byte(0);
  2279. }
  2280.  
  2281.  
  2282. static void
  2283. write_camg ARGS((void))
  2284. {
  2285.     put_big_long(ID_CAMG);
  2286.     put_big_long(CAMGChunkSize);
  2287.     put_big_long(viewportmodes);
  2288. }
  2289.  
  2290.  
  2291. /************ compression ************/
  2292.  
  2293.  
  2294. /* runbyte1 algorithm by Robert A. Knop (rknop@mop.caltech.edu) */
  2295. static int
  2296. runbyte1(size)
  2297.    int size;
  2298. {
  2299.     int in,out,count,hold;
  2300.     register unsigned char *inbuf = coded_rowbuf;
  2301.     register unsigned char *outbuf = compr_rowbuf;
  2302.  
  2303.  
  2304.     in=out=0;
  2305.     while( in<size ) {
  2306.         if( (in<size-1) && (inbuf[in]==inbuf[in+1]) ) {     /*Begin replicate run*/
  2307.             for( count=0,hold=in; in<size && inbuf[in]==inbuf[hold] && count<128; in++,count++)
  2308.                 ;
  2309.             outbuf[out++]=(unsigned char)(char)(-count+1);
  2310.             outbuf[out++]=inbuf[hold];
  2311.         }
  2312.         else {  /*Do a literal run*/
  2313.             hold=out; out++; count=0;
  2314.             while( ((in>=size-2)&&(in<size)) || ((in<size-2) && ((inbuf[in]!=inbuf[in+1])||(inbuf[in]!=inbuf[in+2]))) ) {
  2315.                 outbuf[out++]=inbuf[in++];
  2316.                 if( ++count>=128 )
  2317.                     break;
  2318.             }
  2319.             outbuf[hold]=count-1;
  2320.         }
  2321.     }
  2322.     return(out);
  2323. }
  2324.  
  2325.  
  2326.  
  2327. /************ other utility functions ************/
  2328.  
  2329. static int
  2330. colorstobpp(colors)
  2331.     int colors;
  2332. {
  2333.     int i;
  2334.  
  2335.     for( i = 1; i <= MAXPLANES; i++ ) {
  2336.         if( colors <= (1 << i) )
  2337.             return i;
  2338.     }
  2339.     pm_error("too many planes (max %d)", MAXPLANES);
  2340. }
  2341.  
  2342.  
  2343. static void
  2344. #if __STDC__
  2345. put_big_short(short s)
  2346. #else
  2347. put_big_short(s)
  2348.     short s;
  2349. #endif
  2350. {
  2351.     if ( pm_writebigshort( stdout, s ) == -1 )
  2352.         pm_error( "write error" );
  2353. }
  2354.  
  2355.  
  2356. static void
  2357. put_big_long(l)
  2358.     long l;
  2359. {
  2360.     if ( pm_writebiglong( stdout, l ) == -1 )
  2361.         pm_error( "write error" );
  2362. }
  2363.  
  2364.  
  2365. static void
  2366. write_bytes(buffer, bytes)
  2367.     unsigned char *buffer;
  2368.     int bytes;
  2369. {
  2370.     if( fwrite(buffer, 1, bytes, stdout) != bytes )
  2371.         pm_error("write error");
  2372. }
  2373.  
  2374.  
  2375. static int *
  2376. make_val_table(oldmaxval, newmaxval)
  2377.     int oldmaxval, newmaxval;
  2378. {
  2379.     int i;
  2380.     int *table;
  2381.  
  2382.     table = MALLOC(oldmaxval + 1, int);
  2383.     for(i = 0; i <= oldmaxval; i++ )
  2384.         table[i] = (i * newmaxval + oldmaxval/2) / oldmaxval;
  2385.  
  2386.     return table;
  2387. }
  2388.  
  2389.  
  2390. static void *
  2391. xmalloc(bytes)
  2392.     int bytes;
  2393. {
  2394.     void *mem;
  2395.  
  2396.     mem = malloc(bytes);
  2397.     if( mem == NULL )
  2398.         pm_error("out of memory allocating %d bytes", bytes);
  2399.     return mem;
  2400. }
  2401.  
  2402.  
  2403. static int  gFormat;
  2404. static int  gCols;
  2405. static int  gMaxval;
  2406.  
  2407. static void
  2408. init_read(fp, colsP, rowsP, maxvalP, formatP, readall)
  2409.     FILE *fp;
  2410.     int *colsP, *rowsP;
  2411.     pixval *maxvalP;
  2412.     int *formatP;
  2413.     int readall;
  2414. {
  2415.     ppm_readppminit(fp, colsP, rowsP, maxvalP, formatP);
  2416.     if( readall ) {
  2417.         int row;
  2418.  
  2419.         pixels = ppm_allocarray(*colsP, *rowsP);
  2420.         for( row = 0; row < *rowsP; row++ )
  2421.             ppm_readppmrow(fp, pixels[row], *colsP, *maxvalP, *formatP);
  2422.         /* pixels = ppm_readppm(fp, colsP, rowsP, maxvalP); */
  2423.     }
  2424.     else {
  2425.         pixrow = ppm_allocrow(*colsP);
  2426.     }
  2427.     gCols = *colsP;
  2428.     gMaxval = *maxvalP;
  2429.     gFormat = *formatP;
  2430. }
  2431.  
  2432.  
  2433. static pixel *
  2434. next_pixrow(fp, row)
  2435.     FILE *fp;
  2436.     int row;
  2437. {
  2438.     if( pixels )
  2439.         pixrow = pixels[row];
  2440.     else {
  2441. #ifdef DEBUG
  2442.         static int rowcnt;
  2443.         if( row != rowcnt )
  2444.             pm_error("big mistake");
  2445.         rowcnt++;
  2446. #endif
  2447.         ppm_readppmrow(fp, pixrow, gCols, gMaxval, gFormat);
  2448.     }
  2449.     if( maskrow ) {
  2450.         int col;
  2451.  
  2452.         if( maskfile )
  2453.             pbm_readpbmrow(maskfile, maskrow, maskcols, maskformat);
  2454.         else {
  2455.             for( col = 0; col < gCols; col++ )
  2456.                 maskrow[col] = PBM_BLACK;
  2457.         }
  2458.         if( transpColor ) {
  2459.             for( col = 0; col < gCols; col++ )
  2460.                 if( PPM_EQUAL(pixrow[col], *transpColor) )
  2461.                     maskrow[col] = PBM_WHITE;
  2462.         }
  2463.     }
  2464.     return pixrow;
  2465. }
  2466.  
  2467.  
  2468.